Memra

Byte streams vs character streams

InputStream/OutputStream for raw bytes, Reader/Writer for text — and why the distinction matters.

Two families of streams

Java's classic I/O layer splits into two parallel hierarchies based on what you're moving:

Byte streams (InputStream / OutputStream) move raw binary data — eight bits at a time. Use them for images, audio, serialised objects, or any file where you cannot assume a text encoding.

Character streams (Reader / Writer) move decoded text — they handle charset conversion so your code sees char values rather than raw bytes. Use them whenever you are reading or writing text.

The bridge: InputStreamReader wraps an InputStream and decodes bytes to chars using a specified charset:

Reader reader = new InputStreamReader(System.in, StandardCharsets.UTF_8);

Buffering is almost always the right default — raw streams do one system call per read/write, which is slow. Wrap with a Buffered decorator:

BufferedReader br  = new BufferedReader(new FileReader("notes.txt"));
BufferedWriter bw  = new BufferedWriter(new FileWriter("out.txt"));

The three standard streams:

| Stream | Type | Purpose | |---|---|---| | System.in | InputStream | keyboard / stdin | | System.out | PrintStream | normal output / stdout | | System.err | PrintStream | error output / stderr |

PrintStream (which System.out and System.err use) is a convenience byte stream that adds print/println/printf — it is not a Writer despite printing text.

NORMAL ~/memra/learn/java-from-zero/byte-vs-character-streams utf-8 LF