BufferedReader vs BufferedInputStream
Fast recall
Quick revision
Core answer
BufferedReader buffers characters and supports text operations such as readLine; BufferedInputStream buffers raw bytes and preserves binary data. Choose the reader only after defining the charset, and choose the input stream for binary or undecoded content.Interview-ready guide
Interview answer
BufferedReader reads buffered character data, while BufferedInputStream reads buffered raw bytes. Both reduce small reads from the underlying source, but they work at different layers. A reader gives bytes a text meaning through a charset; an input stream preserves the original byte values.
For a UTF-8 log file, Files.newBufferedReader(log, UTF_8) is the natural choice. It decodes the file and provides readLine(), which returns one line without its line separator. For a PNG, ZIP file, encrypted payload, or binary protocol, use BufferedInputStream because those bytes must not be decoded as text.
When text starts as bytes, InputStreamReader performs the charset decoding and BufferedReader adds character buffering above it. BufferedInputStream instead refills an internal byte array and returns those bytes unchanged. A reader has line operations because line separators are characters; a byte stream cannot know where a text line ends without decoding.
Choose from the meaning of the data, not from which class sounds faster: known text and charset means BufferedReader; binary data means BufferedInputStream. Reading binary data through a Reader can change invalid character sequences and corrupt the result. Both support limited mark and reset, and code should read through the wrapper rather than also reading the wrapped stream directly, because the wrapper may already have read ahead.
BufferedReader vs BufferedInputStream
Direct Answer
BufferedReader buffers characters and supports text operations such as readLine; BufferedInputStream buffers raw bytes and preserves binary data. Choose the reader only after defining the charset, and choose the input stream for binary or undecoded content.
Deep Dive & Architecture
A text pipeline can contain two different kinds of state. The byte source may read ahead, and the charset decoder may retain an incomplete multi-byte character until more bytes arrive. BufferedReader then holds decoded characters and understands line boundaries.
This layered state explains why switching back to the underlying InputStream is unsafe: its physical byte position may be ahead of the characters already delivered to the application. Keep one owner and one logical view of the source.
readLine() recognizes line termination but removes it from the returned String. If a program must preserve exact original separators, it needs a different parsing strategy.
Code Example
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
class BufferedReaderVsInputStream {
public static void main(String[] args) throws Exception {
byte[] utf8 = "first\nsecond".getBytes(StandardCharsets.UTF_8);
try (var reader = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(utf8), StandardCharsets.UTF_8))) {
System.out.println(reader.readLine());
System.out.println(reader.readLine());
}
}
}
Check your understanding
Answer these without looking back at the article.
- Where does charset decoding occur in a BufferedReader pipeline?
- Why should code not read directly from the wrapped InputStream?
- Does readLine preserve the line terminator?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.