В чем разница между InputStream и Reader в Java?

Ответ

InputStream и Reader — это абстрактные классы в Java для чтения данных, но они работают с разными единицами информации.

Ключевое отличие:

  • InputStream предназначен для чтения байтов (8 бит, byte). Он используется для бинарных данных (файлы, изображения, сетевые сокеты).
  • Reader предназначен для чтения символов (16 бит, char), т.е. текстовых данных. Он корректно обрабатывает кодировки символов.

Почему это важно? Символ (char) может кодироваться одним или несколькими байтами в зависимости от кодировки (UTF-8, Windows-1251). Reader выполняет это преобразование автоматически.

Иерархия и примеры:

// InputStream (для байтов)
InputStream is = new FileInputStream("data.bin");
int byteData = is.read(); // Читает один байт

// Reader (для символов/текста)
// FileReader использует кодировку по умолчанию платформы (часто рискованно)
Reader reader1 = new FileReader("text.txt");

// Лучше явно указывать кодировку через InputStreamReader
Reader reader2 = new InputStreamReader(
                    new FileInputStream("text.txt"), 
                    StandardCharsets.UTF_8
                );
int charData = reader2.read(); // Читает один символ (char)

Аналоги для записи: OutputStream (для байтов) и Writer (для символов).

Правило выбора:

  • Используйте InputStream/OutputStream для всего, что не является простым текстом (.jpg, .zip, .pdf, сериализованные объекты).
  • Используйте Reader/Writer (с явно указанной кодировкой, например, UTF-8) для чтения и записи текстовых файлов (.txt, .html, .json, .xml).

Ответ 18+ 🔞

Давай разберём эту дичь, чтобы она в голове наконец улеглась, а не болталась как манда с ушами. Смотри, в чём тут суть.

Есть два главных абстрактных деда, с которых всё начинается: InputStream и Reader. И они, блядь, работают с принципиально разным добром, хоть оба и для чтения.

В чём, сука, разница, если по-простому?

  • InputStream — это для байтов. Для вот этой вот сырой, бинарной хуйни. Картинка, зип-архив, какой-нибудь .exe файл, данные из сети — всё, что не текст в чистом виде. Он читает по одному байту (8 бит, byte). Представь, что ты пьёшь воду из шланга — глотаешь поток, не думая, из чего он состоит.
  • Reader — это уже для символов (букв, знаков). Для текста, мать его. Он оперирует char'ами (16 бит). И вот тут главный фокус: один символ (например, русская "ё" или смайлик) в файле может быть записан НЕСКОЛЬКИМИ байтами, в зависимости от кодировки (UTF-8, Windows-1251 и прочая пиздобратия). Reader — это такой умный переводчик, который берёт этот поток байтов и сам, ебушки-воробушки, собирает из них правильные символы, согласно указанной кодировке. InputStream этого делать не умеет — он тебе байты так и выдаст, а ты потом сам голову ломай.

Иерархия и как этим пользоваться, чтобы не обосраться:

// InputStream (для всего нетекстового, для байтов)
InputStream is = new FileInputStream("photo.jpg");
int byteData = is.read(); // Высосал один байт. Всё.

// Reader (для текста)
// Вариант 1: Наивный и опасный. FileReader возьмёт кодировку по умолчанию системы.
// Если файл в UTF-8, а система в CP1251 — получишь абракадабру. Доверяй, но проверяй, а лучше — не доверяй ни хуя.
Reader reader1 = new FileReader("text.txt");

// Вариант 2: Правильный и взрослый. Берём InputStream и насаживаем на него InputStreamReader,
// где явно, блядь, указываем кодировку. Теперь всё будет чётко.
Reader reader2 = new InputStreamReader(
                    new FileInputStream("text.txt"),
                    StandardCharsets.UTF_8 // Вот, сука, явно сказали!
                );
int charData = reader2.read(); // Прочитал один целый символ (char), а не сранный байт.

Для записи, ясное дело, есть их антиподы: OutputStream (плюёт байтами) и Writer (вываливает символами).

Итоговое правило, которое надо выжечь на жопе:

  • InputStream/OutputStream — для всей не текстовой хуйни: картинки (jpg, png), архивы (zip), программы, PDF-ки.
  • Reader/WriterТОЛЬКО для текста (txt, html, json, xml). И всегда, блядь, явно указывай кодировку (в идеале UTF-8), а не надейся на авось, а то потом волосы на жопе рвать будешь, разбираясь с кракозябрами.