When I first started learning Java file handling, I thought all these classes were just different ways to read and write files. But once I understood how they actually work internally, everything became clearer.
Let’s break it down in a simple way.
Big Picture (How They Are Related)
Java splits file handling into two layers:
Reader (abstract)
↓
FileReader → connects to file
BufferedReader → makes reading faster
Writer (abstract)
↓
FileWriter → connects to file
BufferedWriter → makes writing faster
Think of it like this:
- FileReader / FileWriter → direct connection to the file
- BufferedReader / BufferedWriter → performance layer on top
FileReader — What Really Happens
FileReader fr = new FileReader("file.txt");
int ch = fr.read();
At first glance, it looks simple. But behind the scenes:
- Java requests data from the OS
- OS reads data from disk into memory
- JVM copies it into user space
- You receive one character at a time
Now consider this loop:
while ((ch = fr.read()) != -1)
This leads to:
- Many method calls
- Reading one character repeatedly
- Inefficient performance for large files
The issue is not disk speed — it is how the data is consumed.
BufferedReader — The Improvement
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
This introduces a buffer layer.
What changes:
- Reads a large chunk (around 8KB) at once
- Stores it in memory
- Your program reads from memory instead of disk repeatedly
Example:
String line = br.readLine();
Internally:
- Searches for newline (
\n) - Builds a string
- If newline is not found, it refills the buffer and continues
Instead of multiple disk operations:
- One disk read
- Many fast in-memory reads
Why BufferedReader Is Faster
The performance improvement comes from:
- Fewer system calls
- Lower CPU overhead
- Better memory access patterns
FileWriter — Writing Basics
FileWriter fw = new FileWriter("file.txt");
fw.write("Hello");
What happens:
- Data moves from Java to the OS
- OS writes it to disk
Issue:
- Each write operation may trigger disk activity
- Frequent writes reduce performance
BufferedWriter — Efficient Writing
BufferedWriter bw = new BufferedWriter(new FileWriter("file.txt"));
Now:
- Data is stored in memory first
-
Written to disk only when:
- Buffer is full
- flush() is called
- close() is called
Important:
bw.flush();
This ensures data is written to disk.
Without calling flush:
- Data may remain in memory
- Output may appear incomplete
Design Insight (Decorator Pattern)
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
This is an example of the Decorator Pattern:
- FileReader → provides base functionality
- BufferedReader → enhances it
Benefits of this design:
- Separation of concerns
- Reusable components
- Flexible layering
Why Not Just Use FileReader/FileWriter?
Because they do not scale well.
| Problem | Impact |
|---|---|
| Character-by-character reading | Slow |
| Frequent system calls | High overhead |
| No batching | Poor performance |
Memory vs Performance
Buffered classes:
- Use slightly more memory
- Provide significant performance improvement
A small memory cost results in much faster execution.
Try-With-Resources (Best Practice)
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
// use it
}
Advantages:
- Automatically closes resources
- Prevents memory leaks
- Ensures proper flushing for writers
Top comments (0)