Java I/O Streams — Byte Streams vs Character Streams Explained
Fast recall
Quick revision
Core answer
InputStream/OutputStream, base class reads/writes raw bytes) and character streams (Reader/Writer, reads/writes chars with automatic encoding/decoding). Use byte streams for binary data: images, PDFs, audio, network bytes, serialization. Use character streams for text: log files, CSV, JSON, config files — always specify a charset (StandardCharsets.UTF_8) or face platform-dependent bugs. Wrap raw streams in `BufferedInputStream`/`BufferedReader` for performance (default 8 KB buffer reduces syscalls by ~100×). Bridge between the two with `InputStreamReader`/`OutputStreamWriter` when you need to decode bytes into chars.Whether the candidate understands the fundamental distinction between bytes and characters, the need for explicit charsets, and why buffering matters for performance
Using `FileReader` without specifying charset — uses platform default (Windows-1252, UTF-8 on Linux) causing mojibake in production. Not wrapping in BufferedX and making thousands of one-byte syscalls
Mention Java 11 `Files.readString()`/`Files.writeString()` for small text files, the 8 KB default buffer size, and that `PrintStream` (like `System.out`) silently swallows `IOException` — a common debugging trap
Interview-ready guide
Interview answer
Java I/O has two parallel stream hierarchies.
Byte streams — InputStream and OutputStream
- Read and write raw bytes
- Use for binary data: images, PDFs, audio, network bytes, serialization
- No encoding involved — bytes go in, bytes come out
Character streams — Reader and Writer
- Read and write Java
chars - Automatically decode/encode using a charset like UTF-8
- Use for text: log files, CSVs, JSON, XML, anything humans read
The charset trap is the most common production bug
new FileReader("file")without a charset uses the platform default- Windows might give you windows-1252, Linux UTF-8, Docker sometimes ASCII
- Developer tests on Mac, ships to Windows, text corrupts silently
- Java 18 fixed this (JEP 400 made UTF-8 the default), but older JDKs still bite
- Always pass
StandardCharsets.UTF_8explicitly
Buffering makes a 100× difference
- Raw
FileReadercalls a syscall per character — millions for a medium file BufferedReaderreads ahead into an 8 KB buffer — serves most reads from memoryBufferedReaderalso gives youreadLine()for line-based processing
Bridge classes connect the two families
InputStreamReader(stream, UTF_8)decodes bytes to charsOutputStreamWriter(stream, UTF_8)encodes chars to bytes- Common when reading HTTP response bodies from a
URLConnection
Modern Java 11+ APIs are cleaner
Files.readString(path, UTF_8)— one-liner for small text filesFiles.writeString(path, content, UTF_8)— same for writingFiles.newBufferedReader(path, UTF_8)— buffered, charset-safe, closeable
Recommendation: For any text I/O, reach for Files.newBufferedReader() / Files.newBufferedWriter() with StandardCharsets.UTF_8 and wrap in try-with-resources. For binary I/O, use Files.newInputStream() / Files.newOutputStream() wrapped in BufferedInputStream/BufferedOutputStream. Skip the old FileReader/FileWriter constructors without charset — they're a portability hazard. If the file fits comfortably in memory, Files.readString() / Files.readAllBytes() beats a manual loop every time.
Java I/O Streams — Byte Streams vs Character Streams Explained
Direct Answer
Java I/O streams are sequential data pipelines with two families: byte streams (InputStream/OutputStream, base class reads/writes raw bytes) and character streams (Reader/Writer, reads/writes chars with automatic encoding/decoding). Use byte streams for binary data: images, PDFs, audio, network bytes, serialization. Use character streams for text: log files, CSV, JSON, config files — always specify a charset (StandardCharsets.UTF_8) or face platform-dependent bugs. Wrap raw streams in BufferedInputStream/BufferedReader for performance (default 8 KB buffer reduces syscalls by ~100×). Bridge between the two with InputStreamReader/OutputStreamWriter when you need to decode bytes into chars.
Common Mistakes & Pitfalls
Using FileReader without specifying charset — uses platform default (Windows-1252, UTF-8 on Linux) causing mojibake in production. Not wrapping in BufferedX and making thousands of one-byte syscalls
Check your understanding
Answer these without looking back at the article.
- What's the difference between `PrintStream` and `PrintWriter` — and why can they silently lose data?
- How does Java represent characters internally — UTF-16 or UTF-8?
- What does `BufferedReader.readLine()` consider a line terminator?
- How do you handle a file with unknown encoding?
- What changed in Java 18 JEP 400 around the default charset?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.