Как прочитать 10000 ю строку из файла не читая предыдущих
Обновлено: 07.07.2024
Я пытаюсь прочитать определенную строку из текстового файла, однако я не хочу загружать файл в память (он может стать очень большим).
Я искал, но каждый пример, который я нашел, требует либо чтения каждой строки (это замедлит мой код, поскольку существует более 100000 строк), либо загрузки всего этого в массив и получения правильного элемента (файл будет содержать много строк для ввода).
Пример того, что я хочу сделать:
"код - это не настоящий код, он создан, чтобы показать принцип того, что я хочу"
Есть ли способ сделать это?
Я только что понял, что этот файл тоже будет записан между строками чтения (добавление в конец файла).
Нет, если каждая строка имеет фиксированное количество байтов, нет.
На самом деле вам не нужно хранить каждую строку в памяти - но вам нужно прочитать весь файл, чтобы добраться до нужной строки, иначе вы не будете знать, с чего начать чтение. .
Вот фрагмент кода, который у меня был, который будет читать файл и записывать каждую 10-ю строку, включая первую строку, в новый файл (писатель). Вы всегда можете заменить раздел try на все, что хотите. Чтобы изменить количество строк для чтения, просто измените 0 в операторе if "lc.endsWith (" 0 ")" на любую строку, которую вы хотите прочитать. Но если файл записывается по мере того, как вы его читаете, этот код будет работать только с данными, которые содержатся внутри файла, когда вы запускаете этот код.
Если здесь большое значение имеет производительность, и вы часто читаете случайные строки из статического файла, вы можете немного оптимизировать это, прочитав файл и построив индекс (в основном просто long[] ) начального смещения каждого строка файла.
Как только у вас есть это, вы точно знаете, куда перейти в файле, а затем вы можете прочитать до следующего символа новой строки, чтобы получить полную строку.
Единственный способ сделать это - создать индекс, где находится каждая строка (вам нужно только записать конец каждой строки). Без возможности случайного доступа к строке на основе индекса с самого начала вы должны прочитать каждый байт перед этой строкой.
Кстати: чтение 100000 строк на быстрой машине может занять всего одну секунду.
Для небольших файлов:
Для больших файлов:
1) прочтите строку, которую выбирает пользователь,
Если вам нужно прочитать выбранную пользователем строку только один раз или нечасто (или если файл достаточно мал), вам просто нужно прочитать файл построчно с самого начала, пока вы не дойдете до выбранной строки.
Если, с другой стороны, вам нужно часто читать выбранную пользователем строку, вам следует создать указатель номеров строк и смещений. Так, например, строка 42 соответствует смещению в файле на 2347 байтов. В таком случае в идеале вы должны прочитать весь файл только один раз и сохранить индекс - например, на карте, используя номера строк в качестве ключей и смещения в качестве значений.
2) читать новые строки, добавленные с момента последнего чтения. Я планирую читать файл каждые 10 секунд. У меня есть количество строк, и я могу узнать новые номера строк, но мне нужно прочитать эту строку
Что касается второго пункта, вы можете просто сохранить текущее смещение в файл вместо сохранения текущего номера строки - но, конечно, не помешает продолжить построение индекса, если это будет по-прежнему обеспечивать значительный выигрыш в производительности.
- Используйте RandomAccessFile.seek (длинное смещение), чтобы установить указатель файла на последнее сохраненное смещение (сначала убедитесь, что файл длиннее, чем последнее сохраненное смещение - в противном случае ничего нового не добавлено).
- Используйте RandomAccessFile.readLine (), чтобы прочитать строку файла
- Вызовите RandomAccessFile.getFilePointer (), чтобы получить текущее смещение после чтения строки и, при необходимости, поместить (currLineNo + 1, offset) в индекс.
- Повторяйте шаги 2-3, пока не дойдете до конца файла.
Но не слишком увлекайтесь оптимизацией производительности, если только производительность уже не является проблемой или с большой вероятностью может стать проблемой.
BufferedReader in = новый BufferedReader (новый FileReader ("foo.in"), 1024);
Вы должны читать файл построчно. В противном случае как узнать, что вы дошли до строки 5 (как в вашем примере)?
Вы также можете проверить файлы произвольного доступа, которые могут быть полезно, если вы знаете, сколько байтов в строке, как сказал Джон Скит.
Здравствуете, столкнулся с вопросом доступа к произвольной строки в файле. Если я хочу вывести например 67000 строку . Но не хочу бежать 1, 2, 3. 66999,и наконец 67000. Как можно сделать это быстрее? Например как с массивом? arr[67000]? Слышал o RandomAccessFile, но суть не понял.
Дмитрий, если вы не собираетесь менять файл и он у вас работает в роли БД, то для скорости работы 1 раз считайте файл в лист (или в мап, если вам нужна определенная буква) и им пользуйтесь.
Радо каждого слова читать файл от начала и до конца - будет очень долго (в сравнении с коллекцией). А если взять не модифицируемую коллекцию, то ещё немного в скорости выиграете (совсем чуть-чуть).
Но по каждому слову бегать по всему файлу (в 67к строк) это не то, что нужно
Файл - это плоские данные, где там находятся начала строк, да и вообще, есть ли там строки текста, картинки или музыка - это неизвестно. В файле может быть все что угодно, и вероятно даже без хлеба.
Чтобы получить доступ к конкретной строке, сразу без регистрации и смс, нужно где-то и как-то узнать позицию файла, где эта строка начинается. К примеру, прочитать все строки в файле, записывая в другой файлик места, откуда эта строка начинается, а когда надо будет прочитать нужную строчку - мы читаем весь этот маленький файлик со смещениями, открываем большой файл, через 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 для чтения файлов:
- Буферизатор
- Поток ввода файлов
- Файлы
- Сканер
- Случайный файл
Чтение двоичных файлов и текстовых файлов
- Класс FileInputStream считывает данные файла в поток байтов. Поэтому его следует использовать для двоичных файлов, таких как изображения, pdf, мультимедиа, видео и т.д.
- Текстовые файлы основаны на символах. Мы можем использовать классы Reader , а также потоковые классы для их чтения.
- Файлы и классы сканера можно использовать для чтения текстовых файлов, а не двоичных файлов.
Давайте рассмотрим примеры программ для чтения файла на Java.
1. BufferedReader Читает файл
Мы можем использовать BufferedReader для считывания содержимого текстового файла в массив символов .
BufferedReader эффективен для чтения файла, поскольку он буферизует входные данные из указанного файла. Без буферизации каждый вызов методов read() или readLine() будет считывать байты из файла, затем преобразовываться в символы и возвращаться, что будет очень неэффективно.
В приведенной выше программе я печатаю данные файла на консоль. Давайте рассмотрим другой класс утилит для выполнения операций чтения файлов.
- Прочитайте полный файл в виде строки
- Считывайте файл строка за строкой и возвращайте список строк
- Подсчитайте вхождение строки в данный файл.
2. FileInputStream – Считывание двоичных файлов в байты
Мы всегда должны использовать поток для чтения файлов, не основанных на символах, таких как изображения, видео и т.д.
Операция чтения FileInputStream используется с массивом байтов, в то время как операция чтения BufferedReader использует массив символов.
3. Файлы – Чтение файла в список строк
4. Сканер – Считывает текстовый файл в качестве итератора
Мы можем использовать класс сканера для чтения текстового файла. Он работает как итератор
5. RandomAccessFile – Чтение файлов в режиме только для чтения
Класс RandomAccessFile позволяет нам читать файл в разных режимах. Это хороший вариант, если вы хотите убедиться, что в файле не выполняется случайная операция записи.
Это все для чтения файла на Java с использованием различных классов из Java IO API.
Читайте также: