Java BufferedReader вернулся к началу текстового файла?

В настоящее время у меня есть 2 BufferedReaders, инициализированных в одном и том же текстовом файле. Когда я закончу чтение текстового файла с первым BufferedReader, я использую второй, чтобы сделать еще один проход по файлу сверху. Необходимо несколько проходов через один и тот же файл.

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

Идеи? Пакеты? Либс? Код?

Спасибо, ТиДжей.


person Community    schedule 04.11.2008    source источник


Ответы (5)


В чем недостаток простого создания нового BufferedReader для чтения сверху? Я ожидаю, что операционная система кэширует файл, если он достаточно мал.

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

person Jon Skeet    schedule 04.11.2008

Буферизованные считыватели предназначены для последовательного чтения файла. Вам нужен java.io.RandomAccessFile, а затем вы можете использовать seek(), чтобы перейти в нужное место в файле.

Читатель с произвольным доступом реализован так:

try{
     String fileName = "c:/myraffile.txt";
     File file = new File(fileName);
     RandomAccessFile raf = new RandomAccessFile(file, "rw");
     raf.readChar();
     raf.seek(0);
} catch (FileNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
} catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
}

"rw" — это символ режима, который подробно здесь.

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

person Ryan P    schedule 04.11.2008

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

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

person Davide    schedule 04.11.2008
comment
Не могли бы вы уточнить? У меня есть файл размером 30 МБ, я не могу загрузить его весь в память. Я отсортировал данные и теперь хочу выполнить двоичный поиск непосредственно в файле. Для этого мне нужно случайным образом искать. - person over_optimistic; 23.12.2012
comment
В настоящее время я предполагаю, что вы имеете в виду 30 ГБ, если только вы не используете действительно маленькое встроенное оборудование (но тогда оно было бы бездисковым). В любом случае, случайный поиск на дисках часто полностью разрушает логарифмическую производительность двоичного поиска. Пара альтернатив: 1) выполнение последовательного доступа (да, на диске последовательный поиск может быть быстрее, чем бинарный поиск) или 2) смешанный подход, такой как использование B-дерева en.wikipedia.org/wiki/B-tree Если этих подсказок недостаточно, вы можете задать свой вопрос как отдельный вопрос. комментария (пожалуйста, разместите здесь комментарий со ссылкой на вопрос, чтобы пропинговать меня) - person Davide; 28.12.2012

О пометке/сбросе:

Метод метки в BufferedReader принимает параметр readAheadLimit, который ограничивает, насколько далеко вы можете читать после метки, прежде чем сброс станет невозможным. Сброс на самом деле не означает поиск файловой системы (0), он просто ищет внутри буфера. Чтобы процитировать Javadoc:

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

person Zarkonnen    schedule 05.11.2008

«Вся эта история с mark() и reset() в BufferedReader попахивает плохим дизайном».

почему бы вам не расширить этот класс и сделать так, чтобы он выполнял отметку() в конструкторе(), а затем выполнял поиск(0) в методе topOfFile().

BR,
~A

person anjanb    schedule 04.11.2008