BufferedWriter.newLine: примеры (JAVA)

BufferedWriter.newLine: детали метода и примеры
Раздел: Потоки ввода-вывода (Streams) символьные
BufferedWriter.newLine: void

Общее описание

Метод BufferedWriter.newLine() в Java записывает разделитель строки в связанный поток символов. Под капотом реализовано как запись системного разделителя строки, эквивалент write(System.lineSeparator()). Метод не принимает аргументов и не возвращает значения. Подпись метода:

public void newLine() throws IOException

Ключевые свойства:

  • Записывает разделитель строки, зависящий от платформы (значение System.lineSeparator()).
  • Не выполняет автоматической синхронизации с внешними потоками; буфер может быть не сброшен до flush() или close().
  • Не имеет параметров; возвратного значения нет (void).
  • Может бросить IOException при ошибке ввода/вывода или если поток закрыт.
  • Обычно используется совместно с BufferedWriter, который оборачивает любой Writer (например, FileWriter, OutputStreamWriter).

Типичные сценарии применения: запись многострочных текстовых файлов, генерация логов, формирование протоколов с платформозависимыми разделителями строк. При необходимости явного разделителя (CRLF или LF) можно вместо newLine() записать собственную последовательность.

Краткие примеры

1) Базовая запись в файл с try-with-resources:

import java.io.*;

try (BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"))) {
    bw.write("Первая строка");
    bw.newLine();
    bw.write("Вторая строка");
}
Содержимое файла out.txt (на Unix-подобной системе):
Первая строка
Вторая строка

2) Указание кодировки через OutputStreamWriter:

import java.io.*;
import java.nio.charset.StandardCharsets;

try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8))) {
    bw.write("Строка с юникодом");
    bw.newLine();
}
Файл utf8.txt содержит строку и символ перевода строки в UTF-8.

3) Сравнение с PrintWriter.println:

import java.io.*;

try (PrintWriter pw = new PrintWriter(new FileWriter("pw.txt"))) {
    pw.println("Одна строка"); // добавляет системный разделитель и может автофлашить при println с автосбросом
}
Файл pw.txt содержит одну строку с системным разделителем строки.

Альтернативные способы в Java

  • PrintWriter.println(...): добавляет разделитель строки и поддерживает форматирование. Отличие: PrintWriter не бросает IOException при каждой операции записи, вместо этого устанавливает флаг ошибки.
  • Writer.write(System.lineSeparator()): эквивалент по смыслу, но требует явного указания разделителя.
  • Files.newBufferedWriter(Path, Charset) (NIO.2): удобный фабричный метод для получения BufferedWriter с указанием кодировки и опций открытия файла.
  • Files.write(Path, bytes) и Files.writeString(Path, CharSequence) (Java 11+): подходят для записи готовых строк или списков строк без ручного управления буфером.

Когда что предпочтительнее: для по-строчной записи с контролем буфера и производительности предпочтение у BufferedWriter; для удобства форматирования и печати на консоль удобнее PrintWriter; для краткой записи файлов лучше Files.writeString.

Аналоги в других языках и краткие примеры

PHP (разделитель в константе PHP_EOL):

$f = fopen('php.txt', 'w');
fwrite($f, "Строка1" . PHP_EOL);
fclose($f);
php.txt:
Строка1

JavaScript (Node.js):

const fs = require('fs');
fs.writeFileSync('js.txt', 'A line' + require('os').EOL);
js.txt содержит одну строку и системный разделитель.

Python:

with open('py.txt', 'w', encoding='utf-8') as f:
    f.write('Первая строка\n')
py.txt:
Первая строка

C# (System.IO):

using (var sw = new StreamWriter("csharp.txt"))
{
    sw.WriteLine("Строка C#");
}
csharp.txt содержит строку и разделитель среды выполнения.

Go:

package main
import (
    "os"
    "runtime"
)
func main() {
    f, _ := os.Create("go.txt")
    defer f.Close()
    f.WriteString("Line1\n")
}
go.txt:
Line1

Kotlin (на JVM):

import java.io.BufferedWriter
import java.nio.file.Files
import java.nio.file.Paths

val path = Paths.get("kt.txt")
BufferedWriter(Files.newBufferedWriter(path)).use { bw ->
    bw.write("Kotlin line")
    bw.newLine()
}
kt.txt содержит строку с системным разделителем.

Lua:

local f = io.open('lua.txt', 'w')
f:write('str', '\n')
f:close()
lua.txt:
str

Отличия от Java: в большинстве языков строковый литерал "\n" чаще используется явно. Node.js и PHP предоставляют модуль/константу для системного разделителя. В Java есть удобный объектный метод newLine() в BufferedWriter, абстрагирующий платформу.

Типичные ошибки и примеры

1) Вызов newLine после закрытия потока - IOException:

import java.io.*;

BufferedWriter bw = new BufferedWriter(new FileWriter("err.txt"));
bw.close();
bw.newLine(); // бросит IOException: Stream closed
Исключение: java.io.IOException: Stream closed

2) Ожидание конкретной последовательности символов (например, только LF), тогда как на Windows записывается CRLF:

// код записывает newLine(), а ожидается '\n' в проверке
try (BufferedWriter bw = new BufferedWriter(new FileWriter("eol.txt"))) {
    bw.write("a");
    bw.newLine();
}
// На Windows file содержит 'a\r\n', тест может упасть если ожидался '\n'
Потенциальная ошибка: некорректное сравнение строк при платформозависимых тестах.

3) Отсутствие flush/close - данные могут остаться в буфере до завершения программы:

BufferedWriter bw = new BufferedWriter(new FileWriter("buf.txt"));
bw.write("data");
// если программа не завершит корректно и не закроет bw, часть данных может не попасть в файл
Результат зависит от завершения процесса; может быть неполная запись.

4) Игнорирование IOException у PrintWriter: при замене BufferedWriter на PrintWriter исключения не бросаются, что приводит к молчаливым ошибкам записи.

Изменения и история

Метод BufferedWriter.newLine() присутствует с ранних версий Java ( Java 1.1 ) и своей семантики не изменял. Основные изменения в экосистеме, влияющие на способы записи строк, относятся не к самому методу, а к появлению новых API:

  • Java 7 (NIO.2): добавлены Files.newBufferedWriter и другие удобные фабрики для работы с файлами.
  • Java 11: введен Files.writeString, упрощающий запись текста без ручного буфера.

Внутреннее поведение newLine() осталось прежним: запись системного разделителя строки.

Расширенные примеры и нестандартные сценарии

1) Запись в gzip-архив (сжатый текст) с указанной кодировкой:

Пример java
import java.io.*;
import java.util.zip.GZIPOutputStream;
import java.nio.charset.StandardCharsets;

try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream("a.txt.gz")), StandardCharsets.UTF_8))) {
    bw.write("line1");
    bw.newLine();
    bw.write("line2");
}
Результат: файл a.txt.gz с двумя строками внутри архива, разделёнными системным разделителем.

2) Принудительный CRLF независимо от платформы (например, для протоколов SMTP):

Пример java
try (BufferedWriter bw = new BufferedWriter(new FileWriter("crlf.txt"))) {
    bw.write("header\r\n"); // явная запись CRLF
    bw.write("body\r\n");
}
crlf.txt содержит строки, разделённые '\r\n'.

3) Асинхронная запись через отдельный поток с очередью - пример шаблона producer/consumer:

Пример java
import java.io.*;
import java.util.concurrent.*;

BlockingQueue q = new LinkedBlockingQueue<>();
ExecutorService es = Executors.newSingleThreadExecutor();
// consumer: один поток пишет в файл
es.submit(() -> {
    try (BufferedWriter bw = new BufferedWriter(new FileWriter("log.txt", true))) {
        String s;
        while ((s = q.take()) != null) {
            if ("__END__".equals(s)) break;
            bw.write(s);
            bw.newLine();
        }
    }
});
// producer: несколько мест программы добавляют строки в очередь
q.put("first");
q.put("second");
q.put("__END__");
es.shutdown();
log.txt последовательно содержит строки с разделителями платформы; поток записи гарантирует консистентность записи.

4) Добавление в файл с помощью NIO.2 и newLine (указание опции APPEND):

Пример java
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.BufferedWriter;

Path p = Paths.get("append.txt");
try (BufferedWriter bw = Files.newBufferedWriter(p, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
    bw.write("Добавленная строка");
    bw.newLine();
}
append.txt получает дополнительную строку в конец файла.

5) Создание обёртки Writer, нормализующей все newLine в CRLF: пример декоратора:

Пример java
import java.io.*;

class CRLFWriter extends Writer {
    private final Writer out;
    CRLFWriter(Writer out) { this.out = out; }
    public void write(char[] cbuf, int off, int len) throws IOException { out.write(cbuf, off, len); }
    public void flush() throws IOException { out.flush(); }
    public void close() throws IOException { out.close(); }
    public void newLine() throws IOException { out.write('\r'); out.write('\n'); }
}

// Использование: передача CRLFWriter в BufferedWriter не напрямую, но идея - декорировать вызов newLine
Такой подход позволяет контролировать формат конца строки независимо от платформы.

6) Интеграция в сетевой протокол: запись в OutputStreamWriter для Socket:

Пример java
import java.net.*;
import java.io.*;

Socket s = new Socket("example.com", 1234);
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()))) {
    bw.write("COMMAND arg");
    bw.newLine();
    bw.flush();
}
В сеть отправляется строка с системным разделителем; в протоколах чувствительных к EOL лучше явно писать требуемый набор символов.

джава BufferedWriter.newLine function comments

En
BufferedWriter.newLine Writes a line separator