EMZETT.
Login

BufferedWriter

In short: A character stream that buffers write access before it’s actually written to disk — usually wraps a FileWriter.

In more detail: Buffered data only lands safely on disk when closed (or via explicit flush()) — if the writer isn’t closed properly (e.g. due to a crash), buffered, not-yet-written data can be lost. try-with-resources reliably prevents exactly this problem.

In Depth

try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
    for (int i = 1; i <= 5; i++) {
        bw.write("Line " + i);
        bw.newLine(); // platform-independent line break, better than hardcoded "\n"
    }
} catch (IOException e) {
    System.err.println("Error while writing: " + e.getMessage());
}

bw.newLine() writes the line break matching the current operating system (\n on Linux/macOS, \r\n on Windows) — more portable than a hardcoded "\n". Anyone using new FileWriter("output.txt", true) (second argument true = append mode) appends new lines to the end of an existing file instead of overwriting it. A manual bw.flush() forces buffered data to be written to disk immediately, even before the writer is closed — useful for long-running processes where you don’t want to save progress only at program end.

Why buffering is just as important when writing

Every single write() call on an unbuffered FileWriter can trigger its own expensive system call to the operating system. BufferedWriter instead collects write accesses in memory and only writes them to disk as a larger block at once, once the internal buffer is full, flush() is called, or the writer is closed. For many small write operations (e.g. line by line in a loop), this makes a considerable speed difference.

The risk of incomplete data

This very buffering has a downside: as long as the buffer hasn’t been flushed, the “written” data only exists in the program’s working memory, not on disk. If the program crashes or the process is hard-terminated before close()/flush() is called, this buffered data is lost — the file then only contains the part that was actually already written. try-with-resources guarantees that close() (and thus a final flush()) is reliably called even if an exception occurs within the block:

try (BufferedWriter bw = new BufferedWriter(new FileWriter("critical.log"))) {
    bw.write("Important log entry");
    bw.newLine();
    continueProcessing(); // might throw an exception
    // no matter what happens: bw.close() (including flush) still runs, guaranteed
} catch (IOException e) {
    System.err.println("Error while writing: " + e.getMessage());
}

Don’t forget character encoding

new FileWriter("file.txt") without further specification uses the operating system’s default character encoding, which can lead to inconsistent umlauts between different systems (Windows vs. Linux). Explicitly specifying it is cleaner: new FileWriter("file.txt", StandardCharsets.UTF_8), to always guarantee the same encoding regardless of platform.

See also: BufferedReader, Write Files, try-with-resources