Buffered Streams

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Buffered Streams (BufferedInputStream, BufferedReader, etc.) wrap around standard streams to vastly improve performance.
  • They reduce the number of expensive physical disk/network reads by fetching large chunks of data into an internal RAM array (buffer) all at once.
  • The BufferedReader also provides the incredibly useful readLine() method.

Concept

Accessing a physical Hard Drive or SSD is incredibly slow compared to accessing RAM.

If you use a raw FileReader and call read() 1,000 times, you are asking the Operating System to spin up the hard drive and fetch exactly 1 character… 1,000 separate times. This causes massive CPU overhead and I/O latency.

A Buffered Stream solves this. When you call read() on a BufferedReader for the first time, it secretly grabs 8,192 characters (8KB) from the hard drive in one massive swoop and stores them in a RAM array. It returns the first character to you. The next 8,191 times you call read(), it just instantly returns the data from its RAM array without ever talking to the hard drive!

Examples

import java.io.*;

public class BufferedDemo {
    public static void main(String[] args) {
        
        // We use the Decorator Pattern to wrap a FileReader inside a BufferedReader
        try (FileReader fr = new FileReader("large_log.txt");
             BufferedReader br = new BufferedReader(fr)) {
            
            String line;
            // BufferedReader gives us the magical readLine() method!
            // It reads characters from the buffer until it hits a \n or \r
            while ((line = br.readLine()) != null) {
                System.out.println("LOG: " + line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Interview Questions

Q: What does the flush() method do?
A: When you write to a BufferedWriter, the data doesn’t go to the file immediately; it stays in the RAM buffer until the buffer is full (usually 8KB). If your application crashes before the buffer fills up, all that data in RAM is permanently lost.
Calling flush() forces the buffer to instantly write whatever data it currently holds down to the physical hard drive. Note: Closing the stream (close() or using try-with-resources) automatically calls flush() for you.

Q: Why does wrapping a Stream in a Buffered Stream make it faster? Does the hardware read faster?
A: No, the hardware reads at the same speed. The speed increase comes from reducing the number of System Calls. A system call (asking the OS to read from the disk) requires context-switching the CPU from User Space to Kernel Space, which is highly expensive. A raw stream doing 10,000 reads makes 10,000 system calls. A Buffered Stream reads the same 10,000 characters by making just 2 system calls (grabbing 8KB each time), eliminating 9,998 expensive context switches.