InputStreamReader and OutputStreamWriter

Naveen AnamaneniUpdated · 4 min read
mediumJava 25javaioencoding

InputStreamReader and OutputStreamWriter are the bridges between byte streams and character streams. An InputStreamReader reads bytes from an InputStream and decodes them into characters. An OutputStreamWriter takes characters and encodes them into bytes for an OutputStream. The rule for turning characters into bytes is called a character set (or charset), such as UTF-8. In this lesson, you will learn how these bridges work and why choosing the right charset matters.

Characters and Bytes

A computer stores only bytes. A charset is a table that says which bytes stand for which characters:

CharacterUTF-8 bytesCount
A411 byte
éc3 a92 bytes
₹e2 82 b93 bytes
న (Telugu "na")e0 b0 a83 bytes

UTF-8 can represent every character in every language and is the standard for files and the web. Older charsets such as ISO-8859-1 only cover a few hundred characters.

Constructors

ConstructorDescription
new InputStreamReader(InputStream in, Charset cs)It is used to decode bytes from in into characters.
new OutputStreamWriter(OutputStream out, Charset cs)It encodes characters into bytes for out.

FileReader is simply an InputStreamReader over a FileInputStream, and FileWriter is an OutputStreamWriter over a FileOutputStream.

Example: Encoding and Decoding

Let's see an example that writes text containing non-English characters and reads it back.

Charsets.java▶ Try it
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
 
public class Charsets {
    public static void main(String[] args) throws IOException {
        String text = "Navika ate crème brûlée at a café";
 
        try (Writer w = new OutputStreamWriter(
                new FileOutputStream("note.txt"), StandardCharsets.UTF_8)) {
            w.write(text);
        }
        System.out.println(text.length() + " characters, "
            + Files.size(Path.of("note.txt")) + " bytes");
 
        try (BufferedReader right = new BufferedReader(new InputStreamReader(
                new FileInputStream("note.txt"), StandardCharsets.UTF_8))) {
            System.out.println("UTF-8:      " + right.readLine());
        }
        try (BufferedReader wrong = new BufferedReader(new InputStreamReader(
                new FileInputStream("note.txt"),
                StandardCharsets.ISO_8859_1))) {
            System.out.println("ISO-8859-1: " + wrong.readLine());
        }
    }
}
Output
33 characters, 37 bytes
UTF-8:      Navika ate crème brûlée at a café
ISO-8859-1: Navika ate crème brûlée at a café

Explanation: The text has 33 characters but 37 bytes, because each of the four accented letters takes 2 bytes in UTF-8. Reading with the same charset gives the text back exactly. Reading with the wrong charset turns each byte into a separate wrong character; this garbled text is called mojibake.

Example: Reading the Keyboard

System.in is a byte stream, so to read lines of text from the keyboard you bridge it:

KeyboardBridge.java
BufferedReader keyboard = new BufferedReader(
    new InputStreamReader(System.in, StandardCharsets.UTF_8));
String name = keyboard.readLine();

This is exactly what the Scanner class and Console do for you behind the scenes.

Common Mistakes

Creating new String(bytes) without a charset. Use new String(bytes, StandardCharsets.UTF_8).

Counting characters with Files.size. It returns bytes, which differ from characters in UTF-8.

Using a Reader to copy binary files. The decoding step corrupts the data.

Practice

  1. Easy: Write your name in English and in Telugu to a file with UTF-8, then print the number of characters and bytes.
  2. Harder: Write a method that converts a text file from ISO-8859-1 to UTF-8 using InputStreamReader and OutputStreamWriter.

Quick check: Bridging bytes and characters

4 questions
1What does InputStreamReader do?
2How many bytes does ₹ take in UTF-8?
3What happens when text is read with the wrong charset?
4Which class is an InputStreamReader over a FileInputStream?

Key Takeaways

Was this tutorial helpful?

Lesson 345 of 482