Собственные классы Java для чтения и записи файлов?

Читая некоторые источники о работе с файлами ввода/вывода Java, я узнаю, что для операций ввода и вывода существует более 1 альтернативы.

Это:

  • BufferedReader и BufferedWriter
  • FileReader и FileWriter
  • FileInputStream и FileOutputStream
  • InputStreamReader и OutputStreamWriter
  • Scanner класс

Какая из них лучше всего подходит для управления текстовыми файлами? Какая лучшая альтернатива для сериализации? Что говорит Java NIO об этом?

Ответ 1

Два вида данных

Вообще говоря, есть два "мира":

  • двоичные данные
  • текстовые данные

Когда это файл (или сокет, или BLOB в БД, или...), тогда он всегда является двоичными данными.

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

Двоичные данные

Всякий раз, когда вы хотите обрабатывать двоичные данные, вам необходимо использовать InputStream/OutputStream классы (как правило, все, что содержит Stream в его имени).

Вот почему есть FileInputStream и FileOutputStream: те, кто читает и пишет файлы, и они обрабатывают двоичные данные.

Текстовые данные

Всякий раз, когда вы хотите обрабатывать текстовые данные, вам нужно использовать Reader/Writer classes.

Всякий раз, когда вам нужно преобразовать двоичные данные в текст (или наоборот), вам понадобится некоторая кодировка (общие - это UTF-8, UTF-16, ISO-8859-1 (и связанные с ними) и хорошие старый US-ASCII). "К счастью" на платформе Java также есть что-то, называемое "кодировкой платформы по умолчанию", которое оно будет использовать, когда потребуется, но код не указывает его.

Кодирование по умолчанию платформы - это двухсторонний меч:

  • он упрощает написание кода, потому что вам не нужно указывать кодировку для каждой операции, но
  • он может не соответствовать данным, которые у вас есть: если кодировка по умолчанию для платформы - ISO-8859-1, а файл, который вы читаете, на самом деле является UTF-8, то вы получите скремблированный вывод!

Для чтения мы также должны упомянуть BufferedReader, который можно обернуть вокруг любого другого Reader и добавит возможность обрабатывать сразу все строки.

Scanner - это специальный класс, который предназначен для анализа ввода текста в токены. Это наиболее полезно для структурированного текста, но часто используется на System.in, чтобы обеспечить очень простой способ чтения данных из stdin (т.е. От того, что пользователь вводит на клавиатуре).

Бридгин зазор

Теперь, достаточно смешно есть классы, которые делают мост между этими мирами, которые обычно имеют обе части в своих именах:

  • a InputStreamReader потребляет a InputStream и сам является Reader.
  • a OutputStreamWriter является Writer и записывается в OutputStream.

И тогда есть "классы быстрого доступа", которые в основном объединяют два других класса, которые часто объединяются.

  • a FileReader представляет собой в основном комбинацию a FileInputStream с InputStreamReader
  • a FileWriter представляет собой в основном комбинацию a FileOutputStream с OutputStreamWriter

Обратите внимание, что FileReader и FileWriter имеют существенный недостаток по сравнению с их более сложной "ручной конструкцией": они всегда используют стандартную кодировку платформы, что может и не быть тем, Повторите попытку!

Как насчет сериализации?

ObjectOutputStream и ObjectInputStream - специальные потоки, используемые для сериализации.

Как следует из названия классов, сериализация включает в себя только двоичные данные (даже при сериализации объектов String), поэтому вы хотите использовать только классы *Stream. Пока вы избегаете классов Reader/Writer, вы должны быть в порядке.

Дополнительные ресурсы