Символьные потоки
Текст — это символы, но в файле лежат байты
Для текста удобнее работать не с отдельными байтами, а с символами.
Эту модель дают Reader и Writer:
первый читает символы, второй записывает их.
Но граница между файлом и текстом всё равно проходит через кодировку — правило преобразования байтов в символы и обратно.
Поэтому при чтении текста важно знать, в какой кодировке он сохранён.
Современный код обычно указывает её явно, например UTF_8,
а не полагается на настройки окружения.
try (Reader reader = new InputStreamReader(
new FileInputStream("message.txt"), StandardCharsets.UTF_8)) {
int ch = reader.read();
System.out.println((char) ch);
}
InputStreamReader — это мост между двумя мирами:
он получает байты из InputStream и декодирует их в символы выбранной кодировкой.
В обратную сторону работает OutputStreamWriter.
Reader и Writer работают с char
У символьных потоков есть методы для чтения и записи отдельных символов и массивов char.
Как и у байтовых потоков, чтение возвращает специальное значение -1, когда данные закончились.
char[] buffer = new char[1024];
try (Reader reader = new FileReader("message.txt", StandardCharsets.UTF_8)) {
int read = reader.read(buffer);
System.out.println(read);
}
Здесь число read снова означает фактическое количество полученных элементов,
только теперь речь идёт о символах, а не о сырых байтах.
Запись текста
try (Writer writer = new FileWriter("message.txt", StandardCharsets.UTF_8)) {
writer.write("Hello, Java!");
}
Writer принимает текст как символы, а конкретная реализация отвечает за превращение их в байты.
Это делает намерение кода понятнее: если задача — работать с текстом, символьный API обычно лучше отражает её смысл.