1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Character streams read/write text data (16-bit Unicode chars) with automatic encoding conversion.
- Base classes: Reader (read) and Writer (write).
- Common: FileReader/FileWriter (text files), BufferedReader/BufferedWriter (buffered, readLine()), Print Writer (formatted output, printf()). Always use UTF-8 encoding explicitly! Character streams handle newlines, encoding automatically—use for logs, configs, CSV, any text.
Think of international mail. Byte stream = sending raw envelopes (any language). Character stream = translation service (converts between languages). FileReader = receive already-translated letters. Encoding = language (UTF-8, UTF-16)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Reader: Library lending books (reading text)
- Writer: Author writing books (creating text)
- BufferedReader: Speed reader (reads lines at once, not character-by-character)
3. Technical Mastery (The "Deep Dive")
Common Character Stream Classes
| Class | Purpose | Key Method |
|---|---|---|
| FileReader | Read text file | read() |
| FileWriter | Write text file | write(String) |
| BufferedReader | Buffered text reading | readLine() |
| BufferedWriter | Buffered text writing | newLine() |
| PrintWriter | Formatted writing | println(), printf() |
| InputStreamReader | Byte → Char bridge | Constructor |
| OutputStreamWriter | Char → Byte bridge | Constructor |
4. Interactive & Applied Code
java
import java.io.*;
import java.nio.charset.StandardCharsets;
public class CharacterStreamsDemo {
public static void main(String[] args) {
demonstrateFileReaderWriter();
demonstrateBufferedReaderWriter();
demonstratePrintWriter();
demonstrateEncodingBridge();
}
// FileReader/FileWriter (simple text I/O)
static void demonstrateFileReaderWriter() {
System.out.println("=== FILE READER/WRITER ===");
String file = "sample.txt";
// Write text
try (FileWriter fw = new FileWriter(file)) {
fw.write("Line 1: Hello, World!\n");
fw.write("Line 2: Java Character Streams\n");
fw.write("Line 3: Automatic encoding!");
System.out.println("Text written to file");
} catch (IOException e) {
e.printStackTrace();
}
// Read text (char by char)
try (FileReader fr = new FileReader(file)) {
int ch;
System.out.print("Read text: ");
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
// BufferedReader/BufferedWriter (line-based, efficient)
static void demonstrateBufferedReaderWriter() {
System.out.println("\n=== BUFFERED READER/WRITER ===");
String file = "log.txt";
// Write lines
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write("Log entry 1");
bw.newLine(); // Platform-independent newline
bw.write("Log entry 2");
bw.newLine();
bw.write("Log entry 3");
System.out.println("Lines written");
} catch (IOException e) {
e.printStackTrace();
}
// Read lines (most common pattern!)
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
System.out.println("Read lines:");
while ((line = br.readLine()) != null) {
System.out.println(" " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// PrintWriter (formatted output, auto-flush)
static void demonstratePrintWriter() {
System.out.println("\n=== PRINT WRITER ===");
String file = "report.txt";
try (PrintWriter pw = new PrintWriter(new FileWriter(file))) {
pw.println("Report Generated");
pw.println("================");
pw.printf("Name: %s%n", "John Doe");
pw.printf("Age: %d%n", 30);
pw.printf("Salary: $%.2f%n", 75000.50);
// No exception checking needed (use checkError())
if (pw.checkError()) {
System.out.println("Error occurred");
} else {
System.out.println("Report written successfully");
}
} catch (IOException e) {
e.printStackTrace();
}
}
// InputStreamReader/OutputStreamWriter (encoding bridge)
static void demonstrateEncodingBridge() {
System.out.println("\n=== ENCODING BRIDGE ===");
String file = "utf8.txt";
// Write with explicit UTF-8 encoding
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream(file), StandardCharsets.UTF_8)) {
osw.write("Hello with UTF-8: ñ, é, 中文, 🎉");
System.out.println("Written with UTF-8 encoding");
} catch (IOException e) {
e.printStackTrace();
}
// Read with explicit UTF-8 encoding
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream(file), StandardCharsets.UTF_8)) {
int ch;
System.out.print("Read with UTF-8: ");
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
}5. The Comparison & Decision Layer
| Scenario | Use This | Why |
|---|---|---|
| Reading lines | BufferedReader.readLine() | Most efficient |
| Writing formatted | PrintWriter.printf() | Easy formatting |
| Explicit encoding | InputStreamReader/Writer | Control charset |
| Simple text | FileReader/Writer | Quick and simple |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Why should you avoid FileReader/FileWriter in production?" Answer: No encoding control—uses platform default!
java
// ❌ BAD: Uses platform default (Windows=Cp1252, Linux=UTF-8)
FileReader fr = new FileReader("file.txt");
// Will break on different OS or non-ASCII chars!
// ✅ GOOD: Explicit UTF-8 encoding
Reader reader = new InputStreamReader(
new FileInputStream("file.txt"),
StandardCharsets.UTF_8
);
// Works everywhere!
// ✅ EVEN BETTER: Java 11+ Files API
Reader reader = Files.newBufferedReader(
Paths.get("file.txt"),
StandardCharsets.UTF_8
);Pro-Tip: BufferedReader.readLine() vs Scanner.nextLine():
java
// BufferedReader (faster, simple)
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
// Process line
}
}
// Scanner (slower, but token-based parsing)
try (Scanner sc = new Scanner(new File("file.txt"))) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
// Or: sc.nextInt(), sc.nextDouble(), etc.
}
}Use BufferedReader for simple line reading, Scanner for parsing!