Java BufferedWriter
Table of Contents + β
In the last lesson you learned about Java BufferedReader. Writing has the very same problem and the very same fix. When you save a lot of text, talking to the disk over and over is slow. BufferedWriter solves this by collecting your text in memory first, then sending it to the disk in larger pieces.
π€ The problem BufferedWriter solves
Say your program wants to save a thousand lines:
- The plain
FileWritercan send each piece straight to the disk as you write it. - A disk is slow to talk to. Doing it a thousand times is like a thousand short trips to the store, buying one item each time.
A buffer fixes this:
- The word buffer means a small holding area in memory.
BufferedWriterkeeps your text there instead of running to the disk for every piece.- When it fills up, or when you close the writer, it sends everything in one bigger trip.
- Fewer trips means faster writing.
Picture it: a FileWriter alone carries water one cup at a time. A BufferedWriter fills a bucket first, then pours the whole bucket at once.
Writing can fail, so the methods throw a checked exception called IOException:
- The disk could be full, the folder might not exist, or you may not have permission.
- A checked exception is one the compiler forces you to handle, by catching it or passing it on.
- You cannot ignore it and still compile.
π§± Wrapping a FileWriter
BufferedWriter does not connect to a file by itself. It wraps another writer that does, usually FileWriter. You build it in two layers: the FileWriter is the pipe to the disk, and the BufferedWriter is the speed buffer on top.
Here is the pattern you will use almost every time.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedWriter writer = new BufferedWriter(new FileWriter("greeting.txt"))) { writer.write("Hello, Alex!"); // β
goes into the buffer first System.out.println("Done writing."); } catch (IOException e) { System.out.println("Could not write the file: " + e.getMessage()); } }}Reading the code from the inside out:
new FileWriter("greeting.txt")opens the file, creating it if it does not exist.new BufferedWriter(...)wraps thatFileWriterto add the speed buffer.writer.write("Hello, Alex!")puts the text into the buffer.- The
try (...)is try-with-resources, which closes the writer when the block ends. - Closing sends the buffer to the disk, so the file ends up with your text.
The console prints only one line, but the file now holds your greeting.
Output
Done writing.And the file greeting.txt contains this.
greeting.txt
Hello, Alex!βοΈ write, newLine, and flush
The three main methods you will use all the time:
write(String)adds text to the buffer. No line break, so the nextwritecontinues on the same line.newLine()adds the correct line break for your operating system.flush()forces the buffer to the disk now, without closing the writer.
newLine() matters more than it looks. Windows and Linux use different βend of lineβ characters. Typing "\n" yourself may look wrong on Windows, but newLine() always picks the right one.
This example writes two lines using write and newLine.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedWriter writer = new BufferedWriter(new FileWriter("notes.txt"))) { writer.write("First line of notes."); writer.newLine(); // β
move to the next line writer.write("Second line of notes."); writer.newLine(); System.out.println("Two lines written."); } catch (IOException e) { System.out.println("Could not write: " + e.getMessage()); } }}Notice the order: write some text, newLine to end the line, then write the next. Without the newLine calls, both pieces would sit on one long line.
Output
Two lines written.The file notes.txt now holds two separate lines.
notes.txt
First line of notes.Second line of notes.Call flush() yourself mainly in long-running programs that need each piece on disk immediately, like a live log. Short programs do not need it, because closing the writer flushes for you. More on this soon.
π Writing many lines in a loop
The buffer really shines when you write a lot of text. A loop is the natural way to write many lines, and BufferedWriter keeps it fast because the lines pile up in the buffer instead of each one running to the disk.
This example writes ten numbered lines.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedWriter writer = new BufferedWriter(new FileWriter("lines.txt"))) { for (int i = 1; i <= 10; i++) { writer.write("Line number " + i); // β
each pass adds one line writer.newLine(); } System.out.println("Wrote 10 lines."); } catch (IOException e) { System.out.println("Could not write: " + e.getMessage()); } }}Walking through the loop:
- The counter
igoes from 1 to 10. - Each pass builds a small line of text with the current number.
writeadds that text to the buffer, thennewLineends the line.- All ten lines collect in the buffer and reach the disk together when the writer closes.
Output
Wrote 10 lines.The file lines.txt ends up with all ten lines.
lines.txt
Line number 1Line number 2Line number 3Line number 4Line number 5Line number 6Line number 7Line number 8Line number 9Line number 10This is where the speed difference shows. A plain FileWriter could touch the disk on each write. The buffer makes them travel together in fewer trips, and the more lines you write, the bigger the win.
β Appending instead of overwriting
Here is the part beginners most often get wrong, so read it slowly. There are two modes when you open a file for writing:
- Overwrite mode wipes the file clean and starts fresh. This is the default.
- Append mode keeps the existing content and adds your new text at the end.
- The default overwrite is the trap. Write to an important file the normal way and the old content is gone, with no undo.
- Imagine a log file holding a week of events. Open it the default way, write one line, and you deleted a week of history.
To switch on append mode, pass true as the second argument to FileWriter. The BufferedWriter around it does not change.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { // the true here means "append", not "overwrite" try (BufferedWriter writer = new BufferedWriter(new FileWriter("log.txt", true))) { writer.write("New log entry"); // β
added to the end, old lines kept writer.newLine(); System.out.println("Entry appended."); } catch (IOException e) { System.out.println("Could not append: " + e.getMessage()); } }}The whole difference is that small true:
- With it, each run adds a line to the end.
- Without it, each run erases everything that was there.
- For logs, where every event should be kept, append is what you want.
Output
Entry appended.If log.txt already held two lines and you run this once, the file now has three.
log.txt
Server startedUser logged inNew log entryπ§ The buffer gotcha: flush and close
Remember the buffer, the holding area in memory? It causes one surprise:
- When you call
write, your text often goes into the buffer first, not the disk. - It sits there until the buffer fills up or you send it down on purpose.
- If your program ends or crashes first, the buffered text is lost.
- The file may end up empty or missing your last lines.
Sending the buffered text to the disk is called flushing. There are two ways it happens:
- You call
writer.flush()yourself to force everything out now. - You close the writer, and closing flushes automatically as its last act.
So closing is not just cleanup. It guarantees your data reaches the disk. The clean way to always close is try-with-resources, which you have seen in every example. Java closes the writer when the block ends, even on error. Compare the two styles below.
// β Risky: you must remember to close, and an error may skip itBufferedWriter writer = new BufferedWriter(new FileWriter("data.txt"));writer.write("important data");// if an exception happens here, close() never runs and the buffer is lostwriter.close();
// β
Safe: try-with-resources always closes (and flushes) for youtry (BufferedWriter w = new BufferedWriter(new FileWriter("data.txt"))) { w.write("important data");} // w is closed and flushed here, even if an error happenedSo always open a BufferedWriter with try-with-resources. You get the flush and the close for free, and your data is safe.
This tiny program shows the danger of skipping the close. It writes text but never closes the writer, so the buffer may never reach the disk.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) throws IOException { BufferedWriter writer = new BufferedWriter(new FileWriter("risky.txt")); writer.write("This might never be saved."); // β sits in the buffer // no close(), no flush() β the program just ends here System.out.println("Program finished."); }}The console says the program finished, yet risky.txt can come out empty because the text never left the buffer.
Output
Program finished.The buffer can swallow your data
If text stays in the buffer and the writer is never flushed or closed, that text never reaches the file. Always close the writer, and the easiest way is try-with-resources.
π§ͺ A worked example: overwrite, then append
Letβs tie it together with one realistic run. First we overwrite a fresh file with three lines. Then a separate program appends one line. Watching the file before and after makes the two modes clear.
This first program writes three lines, replacing any old content.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedWriter writer = new BufferedWriter(new FileWriter("scores.txt"))) { writer.write("Alex scored 80"); writer.newLine(); writer.write("Riya scored 95"); writer.newLine(); writer.write("Sam scored 73"); writer.newLine(); System.out.println("Three lines written (overwrite)."); } catch (IOException e) { System.out.println("Write failed: " + e.getMessage()); } }}After this runs, scores.txt holds exactly three lines.
scores.txt
Alex scored 80Riya scored 95Sam scored 73Now a second program appends one more line, keeping the three above. Notice the true for append mode.
import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedWriter writer = new BufferedWriter(new FileWriter("scores.txt", true))) { writer.write("Maya scored 88"); // β
added to the end, others kept writer.newLine(); System.out.println("One line appended."); } catch (IOException e) { System.out.println("Append failed: " + e.getMessage()); } }}After the append, the file has all four lines. The first three stayed because we used append mode.
scores.txt
Alex scored 80Riya scored 95Sam scored 73Maya scored 88Leave out the true in the second program and the file would hold only Maya scored 88. That single argument is the line between adding to your data and destroying it.
β οΈ Common Mistakes
A few BufferedWriter slip-ups to watch for.
- Not closing the writer, so data is lost. Text can stay stuck in the buffer and never reach the disk.
BufferedWriter w = new BufferedWriter(new FileWriter("data.txt"));w.write("hello"); // β never closed, "hello" may be lost
try (BufferedWriter w = new BufferedWriter(new FileWriter("data.txt"))) { w.write("hello"); // β
closed and flushed automatically}- Overwriting instead of appending. Opening for writing erases the file by default, so you can wipe out data without meaning to.
new BufferedWriter(new FileWriter("log.txt")); // β erases the whole lognew BufferedWriter(new FileWriter("log.txt", true)); // β
keeps the log, adds to the end- Forgetting newLine, so everything lands on one line.
writedoes not add a line break for you.
writer.write("First");writer.write("Second"); // β file reads "FirstSecond" on one line
writer.write("First");writer.newLine(); // β
now they sit on separate lineswriter.write("Second");β Best Practices
Habits for writing with BufferedWriter.
- Use try-with-resources every time. It closes the writer and flushes the buffer, so your data is safely saved even when an error happens.
- Wrap a FileWriter, not the other way around. The pattern is
new BufferedWriter(new FileWriter(path)), with the buffer on the outside. - Choose append vs overwrite on purpose. Pass
truetoFileWriterfor logs and growing files. Use the default overwrite only when you truly mean to replace the content. - Use newLine for line breaks. It writes the correct end-of-line for the system, so your file looks right on Windows and Linux alike.
- Call flush only when you need it. For long-running programs that must save as they go,
flush()pushes the buffer out now. Short programs can rely on close. - Always handle IOException. Report failures with a clear message instead of letting the program crash silently.
π§© What Youβve Learned
Nicely done. Letβs recap BufferedWriter.
- β
BufferedWriterwraps another writer (usuallyFileWriter) and writes text faster by buffering it in memory. - β
The pattern is
new BufferedWriter(new FileWriter(path)). - β
Use
write(String)to add text,newLine()for a system-correct line break, andflush()to push the buffer out now. - β Writing in a loop is fast because lines collect in the buffer and travel in fewer disk trips.
- β
Writing overwrites by default; pass
truetoFileWriterfor append mode that keeps existing content. - β
Data can stay in the buffer until flush or close, so always use try-with-resources and handle
IOException.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does BufferedWriter wrap to write to a file?
Why: BufferedWriter wraps another writer, usually a FileWriter, and adds a memory buffer for speed.
- 2
Why can text be lost if you never close a BufferedWriter?
Why: Writes go to the buffer first; without flush or close, that buffered text never reaches the file.
- 3
How do you append with FileWriter instead of overwriting?
Why: new FileWriter(path, true) opens the file in append mode, keeping existing content.
- 4
What does writer.newLine() do?
Why: newLine() writes the correct end-of-line character for the operating system you run on.
π Whatβs Next?
You can now read and write files efficiently with buffered streams. Next, letβs step into a new area: running more than one task at the same time. Threads let your program do several things at once, like writing a file while still responding to the user.