JAVA • INPUT AND OUTPUT

FileWriter/BufferedWriter — Write text files using FileWriter/BufferedWriter (intro)

Learn how Java programs save text data to files on your computer's hard drive.

Historical Context & Motivation

From the earliest days of computing, programs needed a way to store information that would survive after the program stopped running. Data in variables disappears the moment a program ends because it lives in RAM (Random Access Memory), which is temporary. To keep data permanently, programs write it to files on a disk. This concept of persistent storage is one of the most fundamental tasks in all of software development.

Java was designed in the mid-1990s with a rich set of tools for reading and writing files. The original classes, FileWriter and BufferedWriter, were part of the java.io package introduced in Java 1.1. Even though newer APIs exist today, these two classes remain widely taught and used because they are straightforward and demonstrate core I/O concepts clearly.

1995
Java 1.0 Released
Sun Microsystems releases Java with basic I/O classes. File writing is possible but somewhat limited.
1997
Java 1.1 — FileWriter Arrives
Java 1.1 introduces FileWriter and BufferedWriter, making character-based file writing much simpler and more efficient.
2004
Java 5 — Better Utilities
Java 5 adds the Scanner class for reading and the PrintWriter convenience class, but FileWriter and BufferedWriter remain core tools.
2011
Java 7 — Try-With-Resources
Java 7 introduces the try-with-resources statement, making it much easier to close writers safely and avoid resource leaks.
2014
Java 8 — NIO.2 and Files Utility
The java.nio.file.Files class offers one-liner methods for writing files, but FileWriter/BufferedWriter remain the standard for understanding I/O fundamentals.

The central question this lesson addresses is: How does a Java program take text data from memory and save it into a .txt file on disk? Understanding FileWriter and BufferedWriter gives you the tools to answer that question and build programs that create logs, save user data, and export reports.

Core Principles & Definitions

Before diving into code, you need to understand several foundational ideas about how Java handles writing text to files. Java's I/O system is built on the concept of streams — channels through which data flows from your program to an external destination (like a file). When you write text, you use character streams, which are specifically designed to handle human-readable characters rather than raw binary data.

1

FileWriter

A class in java.io that connects your program directly to a file on disk. It writes characters one at a time or in small groups. Think of it as the basic pipeline between your program and the file system.
2

BufferedWriter

A wrapper class that adds a memory buffer (a temporary holding area) around any Writer, including FileWriter. Instead of writing every character immediately to disk, it collects characters and writes them in larger, more efficient batches.
3

Flushing & Closing

Flushing forces any buffered data to be written to disk immediately. Closing a writer flushes it and then releases the file so other programs can use it. Always close your writers when done.
4

IOException

File operations can fail — the disk could be full, the path might be invalid, or you may lack permissions. Java requires you to handle these potential errors using try-catch blocks or throws declarations.
5

Append vs. Overwrite

By default, FileWriter overwrites an existing file. You can pass true as a second constructor argument to switch to append mode, which adds new text to the end of the file instead of erasing it.
✦ KEY TAKEAWAY
Think of FileWriter as a faucet connected directly to a garden — every drop of water (character) goes straight through the pipe. BufferedWriter is like attaching a bucket to that faucet: you collect water in the bucket first, then pour the whole bucket at once. Pouring one big bucket is far more efficient than dripping water one drop at a time. That's why we almost always wrap FileWriter inside BufferedWriter.

Visual Explanation — Data Flow

The following diagram shows how text data flows from your Java program through the BufferedWriter and FileWriter layers until it reaches the actual file on disk. Notice how BufferedWriter sits between your code and FileWriter, collecting characters in its internal buffer before sending them downstream in an efficient batch.

The diagram shows three main layers: your Java code calls bw.write() on the BufferedWriter, which collects characters in an internal buffer. When the buffer fills up or you call flush() or close(), the data is pushed to the FileWriter, which converts the characters to bytes and writes them to the actual file on disk.

The key insight from this diagram is the layered design. FileWriter knows how to talk to the file system, while BufferedWriter knows how to batch characters for efficiency. By wrapping one inside the other, you get both capabilities. This layered wrapping pattern is called the Decorator pattern in software design, and you'll see it throughout Java's I/O library.

How It Works — Method by Method

Now let's look at the key methods you'll use when writing files. Both FileWriter and BufferedWriter provide several methods, but you only need a handful to get started. Understanding what each method does and when to call it is essential for writing correct file-output code.

FileWriter Constructors

Common FileWriter constructors
ConstructorBehavior
new FileWriter("file.txt")Creates or overwrites the file. If the file exists, its contents are erased.
new FileWriter("file.txt", true)Opens the file in append mode. New text is added to the end without erasing existing content.
new FileWriter(new File("file.txt"))Accepts a File object instead of a String path, providing more flexibility for complex file paths.

BufferedWriter Key Methods

Essential BufferedWriter methods
MethodWhat It DoesExample
write(String s)Writes the given string to the buffer.bw.write("Hello");
newLine()Writes a platform-appropriate line separator (works on Windows, Mac, and Linux).bw.newLine();
flush()Forces the buffer contents to be written to the underlying FileWriter immediately.bw.flush();
close()Flushes the buffer, then closes the writer and releases the file handle.bw.close();
write(char[] cbuf, int off, int len)Writes a portion of a character array, starting at offset off for len characters.bw.write(arr, 0, 5);
💡 Why newLine() Matters
Different operating systems use different characters to mark the end of a line. Windows uses \r\n, while macOS and Linux use \n. The newLine() method automatically picks the correct one for whatever system your program is running on, so your files will always look right.

Code Patterns & Resource Management

One of the most important habits in file I/O is properly managing your resources. If you open a file for writing and forget to close it, bad things can happen: data might not actually get saved, the file could become locked so other programs can't use it, or your program could run out of file handles. Java provides two main patterns for safe file writing.

Pattern A (left, green border) uses try-with-resources, which automatically closes the writer when the try block ends — even if an exception is thrown. Pattern B (right, red border) requires manual closing in a finally block. Always prefer Pattern A in modern Java.

The try-with-resources statement (Pattern A) is the modern, preferred approach. You declare your BufferedWriter inside the parentheses of the try statement, and Java guarantees it will be closed when the block finishes executing. This eliminates the entire category of bugs where a programmer forgets to call close(). Any class that implements the AutoCloseable interface can be used with try-with-resources, and both BufferedWriter and FileWriter implement it.

⚠️ Common Mistake
If you create a FileWriter but never close it, the data in the buffer may never reach the file. You could end up with an empty or incomplete file even though your write() calls appeared to work. Always use try-with-resources to avoid this.

Worked Example — Writing a Student Report

Let's walk through a complete example. Suppose you want to write a program that creates a text file called report.txt containing a student's name, grade, and a comment. We'll build this step by step.

Writing a Student Report to a File
1
Step 1 — Import the Required ClassesAt the top of your Java file, add the necessary import statements. You need java.io.BufferedWriter, java.io.FileWriter, and java.io.IOException.
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException;
2
Step 2 — Set Up the Try-With-Resources BlockCreate a BufferedWriter that wraps a FileWriter pointing to "report.txt". Place this inside a try-with-resources statement so the file is closed automatically.
try (BufferedWriter bw = new BufferedWriter(new FileWriter("report.txt"))) {
3
Step 3 — Write the Student DataUse write() to output each line of text and newLine() to move to the next line. Each call adds text to the buffer, which will eventually be flushed to the file.
bw.write("Name: Alice Johnson"); → bw.newLine(); → bw.write("Grade: A"); → bw.newLine(); → bw.write("Comment: Excellent work this semester!");
4
Step 4 — Handle Potential ErrorsAdd a catch block to handle IOException. This could fire if the disk is full, the path is invalid, or you don't have write permission. For now, printing the stack trace is sufficient for debugging.
} catch (IOException e) { e.printStackTrace(); }
5
Step 5 — Verify the OutputAfter running the program, open report.txt in a text editor. You should see three lines of text. The file is created in your project's root directory (or the working directory where you ran the program).
File report.txt contains: Name: Alice Johnson | Grade: A | Comment: Excellent work this semester!

Here is the complete program assembled from the steps above:

📝 Complete Code
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class ReportWriter { public static void main(String[] args) { try (BufferedWriter bw = new BufferedWriter( new FileWriter("report.txt"))) { bw.write("Name: Alice Johnson"); bw.newLine(); bw.write("Grade: A"); bw.newLine(); bw.write("Comment: Excellent work this semester!"); System.out.println("Report saved successfully!"); } catch (IOException e) { e.printStackTrace(); } } }

FileWriter vs. BufferedWriter — Strengths & Trade-offs

You might wonder: if FileWriter can write text on its own, why bother with BufferedWriter at all? The short answer is performance. Every time FileWriter writes to the disk, it makes a system call — a request to the operating system. System calls are slow compared to operations in memory. BufferedWriter dramatically reduces the number of system calls by batching writes together.

Comparison of FileWriter alone vs. BufferedWriter wrapping FileWriter
FeatureFileWriter AloneBufferedWriter + FileWriter
Disk writes per callOne disk write per write() callWrites batched; disk write only when buffer is full or flushed
Speed (many small writes)Slow — many system callsFast — most writes go to memory
Default buffer sizeNo buffer8,192 characters (8 KB)
newLine() methodNot available — must use "\n" manuallyAvailable — platform-independent line separator
Code complexitySlightly simpler (one object)Slightly more setup, but safer and faster
Best use caseWriting a single short stringWriting multiple lines, loops, or large amounts of text
✦ KEY TAKEAWAY
Imagine you're moving boxes from your house to a storage unit across town. FileWriter alone is like driving one box at a time — you make dozens of trips. BufferedWriter is like loading boxes into a moving truck first, then driving them all at once. The total work is the same, but the number of trips (system calls) drops dramatically, saving you a huge amount of time.

Connection to Advanced I/O Techniques

FileWriter and BufferedWriter are your starting point, but Java offers many more file-writing tools for different situations. As you progress, you'll encounter classes that build on the same concepts but offer additional features like formatted output, character encoding control, and high-performance channels.

How FileWriter/BufferedWriter connects to advanced Java I/O
What You Know NowWhat Comes NextWhen to Use It
FileWriterOutputStreamWriterWhen you need explicit control over character encoding (e.g., UTF-8, UTF-16)
BufferedWriterPrintWriterWhen you want convenient println() and printf() methods for formatted output
Writing text (characters)FileOutputStreamWhen you need to write raw bytes (images, PDFs, serialized objects)
Manual write loopsFiles.write() (NIO.2)When you want a one-liner to write a list of strings or a byte array to a file
Single-threaded writingAsynchronousFileChannelWhen you need non-blocking I/O for high-performance server applications

The most important takeaway is that the wrapping pattern you learned here — placing one writer inside another to add functionality — is the same pattern used throughout Java's I/O library. Once you master it with BufferedWriter and FileWriter, you'll find PrintWriter, OutputStreamWriter, and other writers follow exactly the same logic. In AP Computer Science and college courses, you'll also learn about reading files with BufferedReader and FileReader, which mirror these writing classes perfectly.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain in your own words why we wrap a FileWriter inside a BufferedWriter. What would happen if we used FileWriter by itself to write 10,000 individual characters in a loop?
PROBLEM 2 — BASIC CALCULATION
Write a short Java program that creates a file called greeting.txt and writes the text "Hello, World!" on one line and "Welcome to Java I/O." on the next line. Use try-with-resources.
PROBLEM 3 — INTERMEDIATE
You have a String[] names = {"Alice", "Bob", "Charlie", "Diana"}; array. Write a Java method that takes this array and a filename as parameters, then writes each name on its own line in the specified file. If the file already exists, it should append the names rather than overwriting.
PROBLEM 4 — APPLIED
A teacher keeps student test scores in parallel arrays: String[] students = {"Emma", "Liam", "Sophia"}; and int[] scores = {92, 87, 95};. Write a program that creates a file called scores.csv with a header row "Name,Score" followed by one row per student (e.g., "Emma,92"). Explain why CSV format is useful.
PROBLEM 5 — CRITICAL THINKING
Consider the following buggy code: BufferedWriter bw = new BufferedWriter(new FileWriter("log.txt")); bw.write("Entry 1"); bw.write("Entry 2"); The programmer finds that log.txt is sometimes empty or missing data. Identify two distinct bugs in this code and explain how to fix each one. Also, what would the file contain if the code worked correctly — would 'Entry 1' and 'Entry 2' be on the same line or different lines?

Lesson Summary

In this lesson, you learned how to write text files in Java using FileWriter and BufferedWriter. FileWriter creates a direct connection between your program and a file on disk, while BufferedWriter wraps around FileWriter to add an internal buffer that improves performance by reducing the number of disk writes. The standard pattern is to create a BufferedWriter wrapping a FileWriter, use write() and newLine() to output text, and always manage resources with try-with-resources to ensure the file is properly closed.

Key concepts to remember: IOException must be handled with try-catch blocks because file operations can fail. By default, FileWriter overwrites existing files, but passing true to the constructor enables append mode. The Decorator pattern — wrapping one writer inside another — is the foundation of Java's entire I/O system and will carry you forward as you explore PrintWriter, OutputStreamWriter, and the NIO.2 library in future lessons.

Varsity Tutors • Java • FileWriter/BufferedWriter — Write text files using FileWriter/BufferedWriter (intro)