Buffered Input and Output
Why add another layer around a stream
Frequent access to a file or another external source can be noticeably more expensive than working with memory. Buffered streams reduce the number of small operations: they read or accumulate data in blocks inside an internal buffer while user code keeps working with a familiar API.
For bytes, Java provides BufferedInputStream and BufferedOutputStream;
for characters, it provides BufferedReader and BufferedWriter.
They usually wrap an existing stream or reader/writer.
try (InputStream in = new BufferedInputStream(
new FileInputStream("photo.jpg"))) {
byte[] header = in.readNBytes(16);
}
From the outside, this is still an InputStream, so the rest of the code does not need to know
whether a buffer exists inside. This is a good example of stream composition: an extra capability is added by a wrapper.
BufferedReader and reading lines
For text, buffering is especially visible through BufferedReader:
it can read data line by line with readLine().
The returned string does not contain the line terminator, and null means the end of the data.
try (BufferedReader reader = new BufferedReader(
new FileReader("app.log", StandardCharsets.UTF_8))) {
String line = reader.readLine();
System.out.println(line);
}
When flush() is needed
Buffered output may keep written data in memory for some time.
The flush() method asks the stream to pass accumulated data farther down the chain
without closing the stream itself. This matters when another participant must see the output before the resource finishes its work.
try (BufferedWriter writer = new BufferedWriter(
new FileWriter("status.txt", StandardCharsets.UTF_8))) {
writer.write("READY");
writer.flush();
}