Skip to content
Java io 6 min read

BufferedWriter

Writing text files character-by-character can be painfully slow because each call to an unbuffered Writer may trigger a separate system call. BufferedWriter solves this by accumulating your characters in an in-memory buffer and flushing them to the underlying stream in bulk — giving you much faster text output with virtually no code change.

What BufferedWriter Does

BufferedWriter is a character-stream writer that decorates any existing Writer with buffering. It lives in java.io and extends Writer. Instead of sending every character or string straight to the OS, it collects them in an internal char[] buffer. The buffer is flushed to the underlying Writer when it fills up, when you call flush(), or when you call close().

It also provides a very handy newLine() method that writes the platform-appropriate line separator — \n on Unix/macOS, \r\n on Windows — making your code portable without hardcoding a specific newline character.

Tip: Prefer BufferedWriter over FileWriter directly whenever you are writing more than a few lines of text. The performance difference for large files can be enormous.

Constructors

ConstructorBuffer Size
BufferedWriter(Writer out)8192 characters (default)
BufferedWriter(Writer out, int sz)Custom sz characters

The default 8192-character buffer is sensible for most file writes. Increase it when writing very large amounts of text or over a slow network connection.

Basic Usage

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BasicBufferedWrite {
    public static void main(String[] args) throws IOException {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
            bw.write("Hello, BufferedWriter!");
            bw.newLine();
            bw.write("Writing text files has never been easier.");
        } // flush + close happen automatically here
        System.out.println("File written successfully.");
    }
}

Output:

File written successfully.

The resulting output.txt contains two lines. The try-with-resources block calls close() automatically, which first flushes any remaining characters to disk.

Note: FileWriter uses the platform’s default character encoding. To specify a charset explicitly (strongly recommended), use OutputStreamWriter wrapped around a FileOutputStream, then wrap that in BufferedWriter.

Specifying a Character Encoding

Hardcoding a specific encoding avoids garbled characters across different platforms:

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public class EncodedWrite {
    public static void main(String[] args) throws IOException {
        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(
                        new FileOutputStream("utf8_output.txt"),
                        StandardCharsets.UTF_8))) {

            bw.write("Héllo Wörld — UTF-8 characters work fine!");
            bw.newLine();
        }
        System.out.println("UTF-8 file written.");
    }
}

Output:

UTF-8 file written.

Tip: Always use StandardCharsets.UTF_8 unless you have a specific reason to choose a different encoding. It handles all Unicode characters safely.

Writing Multiple Lines

Use write() and newLine() together to build structured text content:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

public class WriteLines {
    public static void main(String[] args) throws IOException {
        List<String> lines = List.of(
            "Line 1: Java is awesome",
            "Line 2: BufferedWriter is fast",
            "Line 3: Always close your streams"
        );

        try (BufferedWriter bw = new BufferedWriter(new FileWriter("lines.txt"))) {
            for (String line : lines) {
                bw.write(line);
                bw.newLine();
            }
        }
        System.out.println("Wrote " + lines.size() + " lines.");
    }
}

Output:

Wrote 3 lines.

Appending to an Existing File

Pass true as the second argument to FileWriter to open the file in append mode:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class AppendToFile {
    public static void main(String[] args) throws IOException {
        // append = true keeps existing content
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("log.txt", true))) {
            bw.write("[INFO] Application started");
            bw.newLine();
        }
        System.out.println("Log entry appended.");
    }
}

Warning: The default FileWriter constructor (without true) truncates the file. If you want to add to existing content, always pass true for the append flag.

Custom Buffer Size

For high-throughput scenarios you can increase the buffer size:

// 64 KB buffer — useful for writing large CSV files or logs
BufferedWriter bw = new BufferedWriter(new FileWriter("large.csv"), 65536);

A larger buffer means fewer system calls but slightly more heap usage. For typical file writes, the default 8192 characters is a good balance.

Flushing the Buffer

Call flush() when a reader needs the data right now, without closing the stream:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FlushDemo {
    public static void main(String[] args) throws IOException {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("progress.log"))) {
            bw.write("Starting long computation...");
            bw.newLine();
            bw.flush(); // guarantee the line reaches the file immediately

            // ... long-running work ...

            bw.write("Done.");
            bw.newLine();
        }
    }
}

Warning: If you skip flush() (or close()) and the JVM exits, any characters still sitting in the internal buffer are silently discarded. Always use try-with-resources or call close() explicitly.

Using NIO’s Files.newBufferedWriter (Java 7+)

The NIO.2 utility class Files provides a clean factory method that also lets you specify charset and open options:

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class NioBufferedWrite {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("report.txt");

        try (BufferedWriter bw = Files.newBufferedWriter(
                path, StandardCharsets.UTF_8, StandardOpenOption.CREATE)) {

            bw.write("Report generated by NIO.2");
            bw.newLine();
        }
        System.out.println("NIO.2 write complete.");
    }
}

Output:

NIO.2 write complete.

This is the most idiomatic approach in modern Java. The NIO.2 Path & Files page covers the full Files API.

Practical Example: Writing a CSV File

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class WriteCsv {
    public static void main(String[] args) throws IOException {
        String[][] data = {
            {"Name", "Age", "City"},
            {"Alice", "30", "London"},
            {"Bob",   "25", "Berlin"},
            {"Carol", "35", "Tokyo"}
        };

        try (BufferedWriter bw = Files.newBufferedWriter(
                Path.of("people.csv"), StandardCharsets.UTF_8)) {

            for (String[] row : data) {
                bw.write(String.join(",", row));
                bw.newLine();
            }
        }
        System.out.println("CSV written successfully.");
    }
}

Output:

CSV written successfully.

The resulting people.csv contains four rows with a platform-appropriate line separator after each one.

Under the Hood

Internally BufferedWriter holds:

  • char[] cb — the write buffer (default 8192 characters)
  • int nextChar — the index of the next free slot in cb
  • int nChars — the total capacity of cb

When you call write(String s, int off, int len), the characters are copied into cb starting at nextChar. If the string is longer than the remaining space, the current buffer is flushed first, then the remaining characters refill the buffer. Writes that exactly fill or exceed the entire buffer are written directly to the underlying Writer in one shot, avoiding a double-copy.

newLine() simply calls write(System.lineSeparator()) — this is resolved at JVM startup and is a constant for the lifetime of the process.

Character encoding is handled by the underlying OutputStreamWriter (or FileWriter), not by BufferedWriter itself. BufferedWriter operates purely on char values; the conversion from char to bytes happens one level down the decorator chain.

Thread safety: BufferedWriter is not thread-safe. Concurrent writes from multiple threads will corrupt the internal buffer state. Use external synchronized blocks or give each thread its own BufferedWriter instance.

Relationship to PrintWriter: PrintWriter also supports println() and can wrap a BufferedWriter. If you need formatted output (printf, format) alongside buffering, stack them: new PrintWriter(new BufferedWriter(new FileWriter("out.txt"))).

Key Methods

MethodDescription
write(int c)Write a single character
write(char[] cbuf, int off, int len)Write a portion of a character array
write(String s, int off, int len)Write a portion of a string
newLine()Write the platform line separator
flush()Flush the buffer to the underlying Writer
close()Flush, then close the stream

BufferedWriter vs FileWriter

FeatureFileWriterBufferedWriter wrapping FileWriter
Each write() callMay hit OS directlyWritten to memory buffer
newLine() methodNot availableYes — platform-safe
Encoding controlPlatform default onlyDelegate to OutputStreamWriter
Performance for small writesSlowFast — writes are batched
OverheadMinimal~16 KB heap for char buffer

For almost every text-writing task, the buffered wrapper wins. Only skip BufferedWriter when you need direct, unbuffered flushing after every single character (extremely rare).

Last updated June 13, 2026
Was this helpful?