Как прочитать 10000 ю строку из файла не читая предыдущих

Обновлено: 07.07.2024

Я пытаюсь прочитать определенную строку из текстового файла, однако я не хочу загружать файл в память (он может стать очень большим).

Я искал, но каждый пример, который я нашел, требует либо чтения каждой строки (это замедлит мой код, поскольку существует более 100000 строк), либо загрузки всего этого в массив и получения правильного элемента (файл будет содержать много строк для ввода).

Пример того, что я хочу сделать:

"код - это не настоящий код, он создан, чтобы показать принцип того, что я хочу"

Есть ли способ сделать это?

Я только что понял, что этот файл тоже будет записан между строками чтения (добавление в конец файла).

Нет, если каждая строка имеет фиксированное количество байтов, нет.

На самом деле вам не нужно хранить каждую строку в памяти - но вам нужно прочитать весь файл, чтобы добраться до нужной строки, иначе вы не будете знать, с чего начать чтение. .

Вот фрагмент кода, который у меня был, который будет читать файл и записывать каждую 10-ю строку, включая первую строку, в новый файл (писатель). Вы всегда можете заменить раздел try на все, что хотите. Чтобы изменить количество строк для чтения, просто измените 0 в операторе if "lc.endsWith (" 0 ")" на любую строку, которую вы хотите прочитать. Но если файл записывается по мере того, как вы его читаете, этот код будет работать только с данными, которые содержатся внутри файла, когда вы запускаете этот код.

Если здесь большое значение имеет производительность, и вы часто читаете случайные строки из статического файла, вы можете немного оптимизировать это, прочитав файл и построив индекс (в основном просто long[] ) начального смещения каждого строка файла.

Как только у вас есть это, вы точно знаете, куда перейти в файле, а затем вы можете прочитать до следующего символа новой строки, чтобы получить полную строку.

Единственный способ сделать это - создать индекс, где находится каждая строка (вам нужно только записать конец каждой строки). Без возможности случайного доступа к строке на основе индекса с самого начала вы должны прочитать каждый байт перед этой строкой.

Кстати: чтение 100000 строк на быстрой машине может занять всего одну секунду.

Для небольших файлов:

Для больших файлов:

1) прочтите строку, которую выбирает пользователь,

Если вам нужно прочитать выбранную пользователем строку только один раз или нечасто (или если файл достаточно мал), вам просто нужно прочитать файл построчно с самого начала, пока вы не дойдете до выбранной строки.

Если, с другой стороны, вам нужно часто читать выбранную пользователем строку, вам следует создать указатель номеров строк и смещений. Так, например, строка 42 соответствует смещению в файле на 2347 байтов. В таком случае в идеале вы должны прочитать весь файл только один раз и сохранить индекс - например, на карте, используя номера строк в качестве ключей и смещения в качестве значений.

2) читать новые строки, добавленные с момента последнего чтения. Я планирую читать файл каждые 10 секунд. У меня есть количество строк, и я могу узнать новые номера строк, но мне нужно прочитать эту строку

Что касается второго пункта, вы можете просто сохранить текущее смещение в файл вместо сохранения текущего номера строки - но, конечно, не помешает продолжить построение индекса, если это будет по-прежнему обеспечивать значительный выигрыш в производительности.

  1. Используйте RandomAccessFile.seek (длинное смещение), чтобы установить указатель файла на последнее сохраненное смещение (сначала убедитесь, что файл длиннее, чем последнее сохраненное смещение - в противном случае ничего нового не добавлено).
  2. Используйте RandomAccessFile.readLine (), чтобы прочитать строку файла
  3. Вызовите RandomAccessFile.getFilePointer (), чтобы получить текущее смещение после чтения строки и, при необходимости, поместить (currLineNo + 1, offset) в индекс.
  4. Повторяйте шаги 2-3, пока не дойдете до конца файла.

Но не слишком увлекайтесь оптимизацией производительности, если только производительность уже не является проблемой или с большой вероятностью может стать проблемой.

BufferedReader in = новый BufferedReader (новый FileReader ("foo.in"), 1024);

Вы должны читать файл построчно. В противном случае как узнать, что вы дошли до строки 5 (как в вашем примере)?

Вы также можете проверить файлы произвольного доступа, которые могут быть полезно, если вы знаете, сколько байтов в строке, как сказал Джон Скит.

Здравствуете, столкнулся с вопросом доступа к произвольной строки в файле. Если я хочу вывести например 67000 строку . Но не хочу бежать 1, 2, 3. 66999,и наконец 67000. Как можно сделать это быстрее? Например как с массивом? arr[67000]? Слышал o RandomAccessFile, но суть не понял.


Вы не уточнили один важный момент - одинаковой ли длинны строки в Вашем файле, потому что если нет, то это невозможно. Нет не одинаковы. Разве так сложно перейти к 800 строке например и что то там с ней сделать? Ведь смысл пробегаться по огромнейшему файлу? К сожалению, переходить можно только к какому-то по счету байту, а не к какой-то строке. Если же есть знание о длинне всех предыдущих строк то можно вычислить к какому байту нужно перейти, в противном случае, к сожалению, необходимо будет прочитать все эти строки. Если я просчитаю все эти строки и выберу определенную. Я ж могу её редактировать как только схочу?(ну в общем) Если информация хранится в текстовом файле такого размера, и регулярны такие операции, как произвольный доступ к строке файла по номеру - значит, пора задуматься об изменении структуры хранения. Для RO-файлов это может быть дополнительный файл-индекс смещений началов строк, например. А если содержимое файла изменяется, причём длина изменённой строки не равна исходной - то пора задуматься о переходе с плоского текста на встраиваемую СУБД.

Дмитрий, если вы не собираетесь менять файл и он у вас работает в роли БД, то для скорости работы 1 раз считайте файл в лист (или в мап, если вам нужна определенная буква) и им пользуйтесь.

Радо каждого слова читать файл от начала и до конца - будет очень долго (в сравнении с коллекцией). А если взять не модифицируемую коллекцию, то ещё немного в скорости выиграете (совсем чуть-чуть).

Но по каждому слову бегать по всему файлу (в 67к строк) это не то, что нужно


4,852 2 2 золотых знака 10 10 серебряных знаков 29 29 бронзовых знаков

Файл - это плоские данные, где там находятся начала строк, да и вообще, есть ли там строки текста, картинки или музыка - это неизвестно. В файле может быть все что угодно, и вероятно даже без хлеба.

Чтобы получить доступ к конкретной строке, сразу без регистрации и смс, нужно где-то и как-то узнать позицию файла, где эта строка начинается. К примеру, прочитать все строки в файле, записывая в другой файлик места, откуда эта строка начинается, а когда надо будет прочитать нужную строчку - мы читаем весь этот маленький файлик со смещениями, открываем большой файл, через RandomAccessFile переходим к нужному месте и оттуда читаем. Фактически, мы таким образом изобрели индексы, а процесс создания таких вспомогательных файликов называется индексированием.

Задача со словарем может быть решена еще проще: зная размер файла, и предварительно отсортировав слова в файле в алфавитном порядке (на самом деле в порядке кодировки, но это тонкости), можно методом половинного деления, искать позицию слова в файле приблизительно, постепенно подбираясь к нужному. Свой словарь я так и делал, разве что seek делал на 200 символов раньше, а потом читал одну строчку и отбрасывал ее, таким образом я находил начало строки. Все собираюсь победить к нем эксепшены и выложить, да времени не найду - может допишите за меня?

Я хочу прочитать последние n строк очень большого файла, не читая весь файл в любой буфер / область памяти с помощью Java.

Я осмотрел API JDK и Apache Commons I / O и не смог найти тот, который подходит для этой цели.

Я думал о том, как хвост или меньше делает это в UNIX. Я не думаю, что они загружают весь файл, а затем показывают последние несколько строк файла. Должен быть аналогичный способ сделать то же самое и в Java.

если вы используете RandomAccessFile , вы можете использовать length и seek чтобы попасть в конкретную точку в конце файла, а затем читать дальше.

если вы обнаружите, что было недостаточно линий, отступите с этой точки и повторите попытку. Как только вы выяснили, где N - Я последняя строка начинается, вы можете искать там и просто читать и печатать.

первоначальное предположение наилучшего предположения может быть сделано на основе ваших данных свойства. Например, если это текстовый файл, возможно, длина строки не будет превышать в среднем 132, поэтому, чтобы получить последние пять строк, начните 660 символов до конца. Затем, если вы ошиблись, попробуйте еще раз в 1320 (вы даже можете использовать то, что вы узнали из последних 660 символов, чтобы настроить это-пример: если эти 660 символов были всего три строки, следующая попытка может быть 660 / 3 * 5, плюс, может быть, немного больше на всякий случай).

Я нашел самый простой способ сделать с помощью ReversedLinesFileReader С Apache commons-io API-интерфейс. Этот метод даст вам строку снизу вверх файла, и вы можете указать n_lines значение для указания количества линий.

RandomAccessFile-хорошее место для начала, как описано в других ответах. Есть один важный нюанс хотя.

если ваш файл не закодирован с кодировкой один байт на символ, readLine() метод не будет работать для вас. И readUTF() не будет работать ни при каких обстоятельствах. (Он читает строку, которой предшествует число символов . )

вместо этого вам нужно будет убедиться, что вы ищете маркеры конца строки таким образом, чтобы уважать границы символов кодировки. Для кодировок фиксированной длины (например, вкусы UTF-16 или UTF-32) необходимо извлечь символы, начиная с байтовых позиций, которые делятся на размер символов в байтах. Для кодировок переменной длины (например, UTF-8) вам нужно найти байт, который должны быть первым байтом символа.

в случае UTF-8 первым байтом символа будет 0xxxxxxx или 110xxxxx или 1110xxxx или 11110xxx . Все остальное - либо второй / третий байт, либо незаконная последовательность UTF-8. См.Стандарт Unicode, Версия 5.2, Глава 3.9, таблица 3-7. Это означает, как указывает обсуждение комментариев, что любые байты 0x0A и 0x0D в правильно закодированном потоке UTF-8 будут представлять символ LF или CR. Таким образом, подсчет байтов является допустимой стратегией реализации (для UTF-8).

определив правильную границу символа, вы можете просто позвонить new String(. ) передача массива байтов, смещение, количество и кодирование, а затем повторно вызовите String.lastIndexOf(. ) для подсчета конца строк.

обратите внимание, что в Apache Commons Collections 4 Этот класс, похоже, был переименован в CircularFifoQueue

У меня была аналогичная проблема, но я не понял других решений.

я использовал это. Надеюсь, это простой код.

вот лучший способ я нашел, чтобы сделать это. Простой и довольно быстрый и оперативную память.

В Java существует ли какой-либо метод для чтения определенной строки из файла? Например, прочитайте строку 32 или любой другой номер строки.

Если у вас нет прежних знаний о строках в файле, нет способа прямого доступа к 32-й строке без чтения 31 предыдущей строки.

Это верно для всех языков и всех современных файловых систем.

Таким образом, вы просто будете читать строки, пока не найдете 32-й.

Для небольших файлов:

Для больших файлов:

Не то, что я знаю, но то, что вы могли бы сделать, это цикл через первые 31 строки, которые ничего не делают, используя функцию readline() BufferedReader

Йоахим прав, и альтернативная реализация Крису (для небольших файлов только потому, что он загружает весь файл), возможно, будет использовать commons-io из Apache (хотя, возможно, вы, возможно, не захотите вводить новую зависимость только для этого, если вы сочтете это полезным для других вещей, хотя, это может иметь смысл).

Вы можете попробовать indexed-file-reader (Apache License 2.0). Класс IndexedFileReader имеет метод readLines (int from, int to), который возвращает SortedMap, чей ключ является номером строки, а значением является строка который был прочитан.

В приведенном выше примере читается текстовый файл, состоящий из 50 строк в следующем формате:

Disclamer: я написал эту библиотеку

Нет, если в этом формате файла не заданы длины строк (например, все строки с фиксированной длиной), вам нужно будет перебирать строки за строкой, чтобы подсчитать их.

Если вы говорите о текстовом файле, то нет никакого способа сделать это, не читая все строки, предшествующие ему. В конце концов, строки определяются наличием новой строки, поэтому ее нужно читать.

Используйте поток, поддерживающий readline, и просто прочитайте первые строки X-1 и дамп результатов, затем обработайте следующий.

Хотя, как сказано в других ответах, невозможно получить точную строку, не зная смещения (указатель) раньше. Итак, я достиг этого, создав временный индексный файл, который сохранит значения смещения каждой строки. Если файл достаточно мал, вы можете просто сохранить индексы (смещение) в памяти, не требуя для этого отдельного файла.

Сложность: это O (n), когда он читает весь файл один раз. Обратите внимание на требования к памяти. Если он слишком большой, чтобы быть в памяти, тогда создайте временный файл, в котором хранятся смещения вместо ArrayList, как показано выше.

Примечание. Если вы хотите в строке "32", вам просто нужно вызвать readLine(), также доступную через 32-х классы других классов. Вышеупомянутый подход полезен, если вы хотите получить определенную строку (на основе номера строки, конечно) несколько раз.

Как прочитать файл на Java? Мы можем использовать классы ввода-вывода Java для чтения текстовых и двоичных файлов, таких как изображения, pdf и т.д., Используя BufferedReader, FileInputStream.

Существует множество различных способов чтения файла на Java. В этом уроке мы рассмотрим 5 различных способов чтения файла на Java.

Различные способы чтения файла на Java

5 классов из API ввода-вывода Java для чтения файлов:

  1. Буферизатор
  2. Поток ввода файлов
  3. Файлы
  4. Сканер
  5. Случайный файл

Чтение двоичных файлов и текстовых файлов

  • Класс FileInputStream считывает данные файла в поток байтов. Поэтому его следует использовать для двоичных файлов, таких как изображения, pdf, мультимедиа, видео и т.д.
  • Текстовые файлы основаны на символах. Мы можем использовать классы Reader , а также потоковые классы для их чтения.
  • Файлы и классы сканера можно использовать для чтения текстовых файлов, а не двоичных файлов.

Давайте рассмотрим примеры программ для чтения файла на Java.

1. BufferedReader Читает файл

Мы можем использовать BufferedReader для считывания содержимого текстового файла в массив символов .

BufferedReader эффективен для чтения файла, поскольку он буферизует входные данные из указанного файла. Без буферизации каждый вызов методов read() или readLine() будет считывать байты из файла, затем преобразовываться в символы и возвращаться, что будет очень неэффективно.

В приведенной выше программе я печатаю данные файла на консоль. Давайте рассмотрим другой класс утилит для выполнения операций чтения файлов.

  1. Прочитайте полный файл в виде строки
  2. Считывайте файл строка за строкой и возвращайте список строк
  3. Подсчитайте вхождение строки в данный файл.

2. FileInputStream – Считывание двоичных файлов в байты

Мы всегда должны использовать поток для чтения файлов, не основанных на символах, таких как изображения, видео и т.д.

Операция чтения FileInputStream используется с массивом байтов, в то время как операция чтения BufferedReader использует массив символов.

3. Файлы – Чтение файла в список строк

4. Сканер – Считывает текстовый файл в качестве итератора

Мы можем использовать класс сканера для чтения текстового файла. Он работает как итератор

5. RandomAccessFile – Чтение файлов в режиме только для чтения

Класс RandomAccessFile позволяет нам читать файл в разных режимах. Это хороший вариант, если вы хотите убедиться, что в файле не выполняется случайная операция записи.

Это все для чтения файла на Java с использованием различных классов из Java IO API.

Читайте также: