Skip to main content

Character Streams

While byte streams handle raw binary files, Character Streams are specifically designed to read and write text files. They automatically handle Unicode character translation between character sets (such as UTF-8 or UTF-16) and the platform's default encoding scheme.

All character stream classes descend from the abstract classes java.io.Reader (for reading) and java.io.Writer (for writing).


Reader and Writer

These classes act as the character equivalents to InputStream and OutputStream, but they operate on char values (16-bit) instead of byte values (8-bit).

Core Methods of Reader

  • int read(): Reads a single character. Returns the character as an integer in the range 0 to 65535, or -1 if the end of the stream has been reached.
  • int read(char[] cbuf): Reads characters into an array. Returns the number of characters read, or -1 if EOF.
  • void close(): Closes the stream and releases system resources.

Core Methods of Writer

  • void write(int c): Writes a single character.
  • void write(char[] cbuf): Writes an array of characters.
  • void write(String str): Writes a string of text directly to the stream.
  • void close(): Closes the stream, flushing it first.

FileReader and FileWriter

These are the primary concrete implementations for reading and writing text files.

[!IMPORTANT] When using FileReader and FileWriter, Java uses the host operating system's default character encoding (e.g., UTF-8 on macOS/Linux, or often Windows-1252 on older Windows systems) unless you explicitly specify the character encoding. To specify an encoding, you can pass a Charset object or use InputStreamReader and OutputStreamWriter wrapper classes in older Java versions.


Practical Code Example: Writing and Reading Text

The following example demonstrates how to write multiple lines of text to a file using FileWriter, and then read the contents back into memory using FileReader with a character buffer array (char[]).

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamDemo {
public static void main(String[] args) {
String filename = "notes.txt";

// 1. Writing to a file using FileWriter
try (FileWriter writer = new FileWriter(filename)) {
writer.write("Hello, CodeNBuild!\n");
writer.write("This is a tutorial on Java Character Streams.\n");
writer.write("It automatically handles UTF-8 character encoding.");
System.out.println("Successfully wrote text to " + filename);
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
e.printStackTrace();
}

// 2. Reading from a file using FileReader
System.out.println("\n--- Reading File Contents ---");
try (FileReader reader = new FileReader(filename)) {
char[] buffer = new char[1024];
int charsRead;

// read(buffer) fills the char array and returns count of characters read
while ((charsRead = reader.read(buffer)) != -1) {
// Convert the read characters into a String to display them
String content = new String(buffer, 0, charsRead);
System.out.print(content);
}
System.out.println(); // Print a newline at the end

} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
e.printStackTrace();
}
}
}

Byte Streams vs. Character Streams: Which to Use?

If you are dealing with plain text files (like .txt, .csv, .json, .html), always use Character Streams. Under the hood, Java converts the bytes to characters according to the character set.

If you are dealing with non-text files (like .png, .jpg, .pdf, .mp3, .class), use Byte Streams. Using character streams on binary files can corrupt the data because certain binary sequences might be interpreted as illegal Unicode characters and replaced with placeholder characters.