Потоки символов
Reader и Writer работают с UTF-16 code units (char). На границе с байтами всегда участвует Charset.
try (BufferedReader reader = Files.newBufferedReader(
path, StandardCharsets.UTF_8);
BufferedWriter writer = Files.newBufferedWriter(
target, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
}Кодировку лучше указывать явно. Иначе default charset зависит от JDK/окружения, а файл может читаться не там, где был записан.
Reader.read()
Как и байтовый stream, одиночный read() возвращает int: значение code unit 0..65535 или -1 для EOF.
int unit;
while ((unit = reader.read()) != -1) {
char ch = (char) unit;
}Одна code unit может быть половиной surrogate pair; для полноценной Unicode-обработки удобнее прочитать строку и идти по code points.
Обертки
InputStreamReaderиOutputStreamWriter— мост byte ↔ char;BufferedReader.readLine()читает строку без разделителя;StringReader/StringWriter— текст в памяти;PrintWriter.printf()— форматированный вывод;Scanner— токенизация и примитивы с учетом locale, но не самый быстрый parser.
PrintWriter по умолчанию не бросает IOException из методов записи: ошибку проверяют checkError(). Это важное отличие от BufferedWriter.
Кодировка — часть контракта
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
String restored = new String(bytes, StandardCharsets.UTF_8);Нельзя декодировать произвольные chunks независимо: multibyte-последовательность UTF-8 может пересекать границу. InputStreamReader хранит промежуточное состояние decoder.
На собеседовании
- InputStream и Reader? Байты против UTF-16 code units.
- Кто превращает байты в символы? Decoder выбранного Charset.
- Возвращает ли readLine разделитель? Нет.
- Почему указывать UTF-8 явно? Не зависеть от окружения и зафиксировать формат.
- Чем опасен PrintWriter? Может скрывать IOException; проверять
checkError.