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
BufferedWriteroverFileWriterdirectly whenever you are writing more than a few lines of text. The performance difference for large files can be enormous.
Constructors
| Constructor | Buffer 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:
FileWriteruses the platform’s default character encoding. To specify a charset explicitly (strongly recommended), useOutputStreamWriterwrapped around aFileOutputStream, then wrap that inBufferedWriter.
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_8unless 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
FileWriterconstructor (withouttrue) truncates the file. If you want to add to existing content, always passtruefor 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()(orclose()) and the JVM exits, any characters still sitting in the internal buffer are silently discarded. Always use try-with-resources or callclose()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 incbint nChars— the total capacity ofcb
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
| Method | Description |
|---|---|
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
| Feature | FileWriter | BufferedWriter wrapping FileWriter |
|---|---|---|
Each write() call | May hit OS directly | Written to memory buffer |
newLine() method | Not available | Yes — platform-safe |
| Encoding control | Platform default only | Delegate to OutputStreamWriter |
| Performance for small writes | Slow | Fast — writes are batched |
| Overhead | Minimal | ~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).
Related Topics
- BufferedReader — the read-side counterpart for efficient line-by-line text input
- FileWriter — the unbuffered character writer that
BufferedWritertypically wraps - PrintWriter — adds
println()andprintf()formatting on top of anyWriter - InputStreamReader / OutputStreamWriter — bridge streams for explicit charset control
- NIO.2: Path & Files — modern file I/O with
Files.newBufferedWriter() - Byte vs Character Streams — when to use
WritervsOutputStream