Buffered streams build on top of node streams (such as FileInputStream/FileOutputStream or FileReader/FileWriter) to reduce direct interaction with the underlying storage, thereby improving throughput. They achieve this by maintaining an internal buffer that accumulates data before reading from or writing to the hardware.
| Abstract Base | Node (File) Streams | Buffered Streams (Processing) |
|---|---|---|
InputStream |
FileInputStream |
BufferedInputStream |
OutputStream |
FileOutputStream |
BufferedOutputStream |
Reader |
FileReader |
BufferedReader |
Writer |
FileWriter |
BufferedWriter |
Why bufffering matters
Minimising system calls is the key. Reading a file byte by byte triggers a separate I/O request for each byte—an enormous overhead. A BufferedInputStream reads a large chunk of bytes into its internal buffer in one operation and then serves subsequent read requests from memory. Likewise, BufferedOutputStream collects written bytes into a buffer and flushes them in larger, more efficient blocks.
Implementation steps
- Create
Fileobjects and wrap them with the appropriate node and buffered streams. - Read or write using the buffered stream’s methods (
read,write,readLine,newLine,flush). - Close resources. Closing the outermost stream automatically closes the inner streams, especially when using
try-with-resources.
Example 1 – Copying an image with BufferedInputStream / BufferedOutputStream
import java.io.*;
public class ImageCopyWithBuffer {
public static void main(String[] args) {
String source = "original.jpg";
String target = "duplicate.jpg";
try (
FileInputStream fin = new FileInputStream(source);
BufferedInputStream bin = new BufferedInputStream(fin);
FileOutputStream fout = new FileOutputStream(target);
BufferedOutputStream bout = new BufferedOutputStream(fout)
) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = bin.read(buffer)) != -1) {
bout.write(buffer, 0, bytesRead);
}
bout.flush();
System.out.println("Copy completed.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Example 2 – Measuring the speed difference
The following comparison uses a deliberately tiny 10‑byte array to amplify the effect of buffering. One method copies a file using plain FileInputStream/FileOutputStream, the other uses bufffered wrapers.
import java.io.*;
public class CopyPerformanceComparison {
public static void main(String[] args) throws IOException {
File src = new File("test_photo.jpeg");
File dest1 = new File("copy1.jpg");
File dest2 = new File("copy2.jpg");
long time1 = copyWithNormalStream(src, dest1);
long time2 = copyWithBufferedStream(src, dest2);
System.out.println("Unbuffered time: " + time1 + " ms");
System.out.println("Buffered time: " + time2 + " ms");
}
private static long copyWithNormalStream(File src, File dest) throws IOException {
long start = System.currentTimeMillis();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dest)) {
byte[] buf = new byte[10];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
}
return System.currentTimeMillis() - start;
}
private static long copyWithBufferedStream(File src, File dest) throws IOException {
long start = System.currentTimeMillis();
try (FileInputStream fin = new FileInputStream(src);
BufferedInputStream bin = new BufferedInputStream(fin);
FileOutputStream fout = new FileOutputStream(dest);
BufferedOutputStream bout = new BufferedOutputStream(fout)) {
byte[] buf = new byte[10];
int len;
while ((len = bin.read(buf)) != -1) {
bout.write(buf, 0, len);
}
}
return System.currentTimeMillis() - start;
}
}
Typical output (values vary by hardware):
Unbuffered time: 1463 ms
Buffered time: 92 ms
Example 3 – Reading text with BufferedReader
BufferedReader offers the convenient readLine() method, which reads a full line without the line‑termination characters. It returns null when the end of the stream is reached.
import java.io.*;
public class ReadTextWithBufferedReader {
public static void main(String[] args) {
File file = new File("sample.txt");
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Example 4 – Writing text with BufferedWriter
When copying text files, remember that readLine() strips newline characters. Use newLine() to insert the platform‑dependent line separator, and consider calling flush() to ensure buffered data is pushed to disk immediately.
import java.io.*;
public class WriteTextWithBufferedWriter {
public static void main(String[] args) {
File input = new File("sample.txt");
File output = new File("output.txt");
try (
BufferedReader reader = new BufferedReader(new FileReader(input));
BufferedWriter writer = new BufferedWriter(new FileWriter(output))
) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
writer.flush(); // forces immediate write; optional if close() is called later
}
System.out.println("File copied.");
} catch (IOException e) {
e.printStackTrace();
}
}
}