Карта / I/O и файлы / Reader / Writer

Reader / Writer

InputStream/OutputStream работают с байтами. Reader/Writer — с символами (текстом). Разница важна: один русский символ в UTF-8 занимает 2–4 байта. Если читать байтами и пытаться выводить как текст — кракозябры. Reader сам занимается декодированием байт → символы.

// Читаем текстовый файл
try (Reader reader = new FileReader("text.txt", StandardCharsets.UTF_8)) {
    int c;
    while ((c = reader.read()) != -1) {
        System.out.print((char) c);
    }
}

// Пишем текст в файл
try (Writer writer = new FileWriter("output.txt", StandardCharsets.UTF_8)) {
    writer.write("Привет, мир!");
}

На практике почти всегда используют обёртки для удобства:

// BufferedReader — читать построчно
try (BufferedReader br = new BufferedReader(
        new FileReader("log.txt", StandardCharsets.UTF_8))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

// PrintWriter — писать с println / printf
try (PrintWriter pw = new PrintWriter(
        new FileWriter("report.txt", StandardCharsets.UTF_8))) {
    pw.println("Строка 1");
    pw.printf("Число: %d%n", 42);
}
Копнуть глубже

InputStreamReader — мост между байтами и символами. Когда у вас InputStream (например, от HTTP-соединения) но нужно читать текст — оборачиваете в InputStreamReader с явной кодировкой:

InputStream raw = httpConnection.getInputStream();
BufferedReader text = new BufferedReader(
    new InputStreamReader(raw, StandardCharsets.UTF_8)
);

Никогда не используйте new FileReader("file.txt") без указания кодировки — он возьмёт системную кодировку платформы, и на разных машинах поведение разное. Всегда явно: StandardCharsets.UTF_8.

System.in, System.out, System.err — тоже потоки:

  • System.inInputStream (байты с клавиатуры)
  • System.outPrintStream (байтовый, но с методами как у PrintWriter)
  • Scanner(System.in) — удобная обёртка для чтения с консоли

StringWriter и StringReader — когда нужно «писать в строку» через Writer-интерфейс:

StringWriter sw = new StringWriter();
sw.write("Hello");
sw.write(" World");
String result = sw.toString(); // "Hello World"

Полезно для тестирования кода, который принимает Writer.

🎤 Закрыл тему, если можешь объяснить:
• чем Reader/Writer отличаются от InputStream/OutputStream и когда что использовать;
• почему нужно явно указывать кодировку и как сделать мост из InputStream в Reader (если дошёл до 2-го слоя).