Java чтение файла разными методами

кажется, что есть много, много способов прочитать текстовые файлы в Java (BufferedReader, DataInputStream etc.) Мой личный фаворит Scanner С File в конструкторе (он просто проще, лучше работает с обработкой данных mathy и имеет знакомый синтаксис).

Борис паук также упомянул Channel и RandomAccessFile.

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

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

3 ответов


давайте начнем с самого начала. Вопрос в том, что ты хочешь делать?

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

  1. File(Input|Output)Stream - прочитайте эти байты как поток byte.
  2. File(Reader|Writer) - чтение из потока байтов в виде потока char.
  3. Scanner - читать из потока char и tokenise его.
  4. RandomAccessFile - прочитайте эти байты как searchable byte[].
  5. FileChannel - прочитайте эти байты безопасным многопоточным способом.

поверх каждого из них есть декораторы, например, вы можете добавить буферизацию с помощью BufferedXXX. Вы можете добавить осознание linebreak к FileWriter С PrintWriter. Вы могли бы превратить InputStream на Reader С InputStreamReader (в настоящее время единственный способ указать кодировку для Reader).

так когда бы я не хотел использовать его [a Scanner]?.

вы бы не использовали Scanner если вы хотите, (вот некоторые примеры):

  1. читать в данных как bytes
  2. чтение в сериализованном объекте Java
  3. скопировать bytes из одного файла в другой, возможно, с некоторой фильтрацией.

это также ничего не стоит, что Scanner(File file) конструктор принимает File открывает FileInputStream С кодировка по умолчанию платформы - это почти всегда плохо идея. Общепризнано, что вы должны указать кодировку явно, чтобы избежать неприятных ошибок на основе кодирования. Далее поток не буферизуется.

так что вам может быть лучше с

try (final Scanner scanner = new Scanner(new BufferedInputStream(new FileInputStream())), "UTF-8") {
    //do stuff
}

некрасиво, я знаю.

стоит отметить, что Java 7 предоставляет дополнительный уровень абстракции для удаления необходимость перебирать файлы-они находятся в файлы класс:

byte[] Files.readAllBytes(Path path)
List<String> Files.readAllLines(Path path, Charset cs)

оба этих метода считывают весь файл в память, что может быть нецелесообразно. В Java 8 это улучшить, добавив поддержку новых Stream API:

Stream<String> Files.lines(Path path, Charset cs)
Stream<Path> Files.list(Path dir)

например, чтобы получить поток слова из Path вы можете сделать:

    final Stream<String> words = Files.lines(Paths.get("myFile.txt")).
            flatMap((in) -> Arrays.stream(in.split("\b")));

SCANNER:

может анализировать примитивные типы и строки с помощью регулярных выражений. Сканер разбивает входные данные на маркеры с помощью шаблона разделителя, который по умолчанию соответствует пробелам. Полученные маркеры затем могут быть преобразованы в значения различных типов.подробнее можно прочитать на http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html

DATA INPUT STREAM:

позволяет приложению читать примитивные типы данных Java из базового ввода трансляция в машинно-независимым способом. Приложение использует поток вывода данных для записи данных, которые впоследствии могут быть прочитаны потоком ввода данных.DataInputStream не обязательно безопасен для многопоточного доступа. Безопасность потоков является необязательной и является ответственностью пользователей методов этого класса. Подробнее можно прочитать наhttp://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html

BufferedReader:

читает текст из символьного входного потока, буферизация символы, чтобы обеспечить эффективное чтение символов, массивов и строк.Может быть указан размер буфера или использован размер по умолчанию. Значение по умолчанию достаточно велико для большинства целей.Как правило, каждый запрос на чтение, выполняемый считывателем, вызывает соответствующий запрос на чтение базового символа или потока байтов. Поэтому рекомендуется обернуть BufferedReader вокруг любого читателя, операции чтения() которого могут быть дорогостоящими, например FileReaders и InputStreamReaders. Для пример,

BufferedReader in   = new BufferedReader(new FileReader("foo.in"));

будет буферизировать входные данные из указанного файла. Без буферизации каждый вызов read() или readLine () может привести к считыванию байтов из файла, преобразованию в символы, а затем возвращению, что может быть очень неэффективным.Программы, использующие DataInputStreams для текстового ввода, можно локализовать, заменив каждый DataInputStream соответствующим BufferedReader.Более подробно на http://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html


Примечание: этот подход устарел. Как отмечает Борис в своем комментарии. Я оставлю это здесь для истории, но вы должны использовать методы, доступные в JDK.

Это зависит от того, какую работу вы делаете, и размер файла, который Вы читаете.

в большинстве случаев я рекомендую использовать commons-io для небольших файлов.

byte[] data = FileUtils.readFileToByteArray(new File("myfile"));

вы можете прочитать его как строку или массив символов...

теперь вы передаете большие файлы, или изменение частей файла непосредственно в файловой системе, то лучше всего использовать RandomAccessFile и потенциально даже FileChannel, чтобы сделать стиль "nio".