Lesson Completion
Back to course

Introduction to Java I/O: Reading and Writing Data

Beginner
12 minutes4.9Java

1. The Hook (The "Byte-Sized" Intro)

In a Nutshell: Java I/O (Input/Output) handles data transfer between program and external sources (files, network, console). Streams are sequences of data. Byte streams (InputStream/OutputStream) handle raw binary data (images, audio). Character streams (Reader/Writer) handle text with encoding support (UTF-8). java.io package provides traditional I/O, java.nio offers modern non-blocking I/O. Always close streams to prevent resource leaks!

Think of water pipeline. Stream = continuous flow of water. Byte stream = raw water pipe (any liquid). Character stream = filtered water pipe (drinking water only). You must turn off the tap (close stream) when done!


2. Conceptual Clarity (The "Simple" Tier)

💡 The Analogy: The Post Office

  • InputStream: Receiving mail (reading data IN)
  • OutputStream: Sending mail (writing data OUT)
  • Buffering: Mail truck collects many letters at once (faster than one-by-one)

I/O Stream Hierarchy

graph TD A[Stream] --> B[Byte Streams] A --> C[Character Streams] B --> D[InputStream] B --> E[OutputStream] C --> F[Reader] C --> G[Writer] D --> H[FileInputStream] D --> I[BufferedInputStream] E --> J[FileOutputStream] E --> K[BufferedOutputStream] F --> L[FileReader] F --> M[BufferedReader] G --> N[FileWriter] G --> O[BufferedWriter]

3. Technical Mastery (The "Deep Dive")

Byte vs Character Streams

FeatureByte StreamsCharacter Streams
Base classInputStream/OutputStreamReader/Writer
Data unit8-bit byte16-bit char (Unicode)
Use forBinary files (images, audio)Text files
EncodingNoneUTF-8, UTF-16, etc.
ExampleFileInputStreamFileReader

The "Why" Paragraph

Why separate byte and character streams? Before Java, all I/O was byte-based—reading text required manual encoding conversion. Character streams (Java 1.1+) handle encoding automatically, converting bytes ↔ chars using Charset. Use byte streams for binary data (images, PDFs), character streams for text (logs, configs). Wrong choice = corrupted data!


4. Interactive & Applied Code

java
import java.io.*; public class IOIntroDemo { public static void main(String[] args) { demonstrateByteStream(); demonstrateCharacterStream(); demonstrateBuffering(); } // BYTE STREAM: Binary file static void demonstrateByteStream() { System.out.println("=== BYTE STREAM ==="); String file = "data.bin"; // Write bytes try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(65); // Writes byte 'A' fos.write(66); // Writes byte 'B' fos.write(67); // Writes byte 'C' System.out.println("Written bytes to " + file); } catch (IOException e) { e.printStackTrace(); } // Read bytes try (FileInputStream fis = new FileInputStream(file)) { int data; System.out.print("Read bytes: "); while ((data = fis.read()) != -1) { System.out.print((char) data + " "); } System.out.println(); } catch (IOException e) { e.printStackTrace(); } } // CHARACTER STREAM: Text file static void demonstrateCharacterStream() { System.out.println("\n=== CHARACTER STREAM ==="); String file = "data.txt"; // Write text try (FileWriter fw = new FileWriter(file)) { fw.write("Hello, Java I/O!\n"); fw.write("Character streams handle encoding automatically."); System.out.println("Written text to " + file); } catch (IOException e) { e.printStackTrace(); } // Read text try (FileReader fr = new FileReader(file)) { int data; System.out.print("Read text: "); while ((data = fr.read()) != -1) { System.out.print((char) data); } System.out.println(); } catch (IOException e) { e.printStackTrace(); } } // BUFFERING: Dramatically faster static void demonstrateBuffering() { System.out.println("\n=== BUFFERING PERFORMANCE ==="); String file = "large.txt"; int iterations = 100000; // Without buffering (slow) long start = System.currentTimeMillis(); try (FileWriter fw = new FileWriter(file)) { for (int i = 0; i < iterations; i++) { fw.write("A"); // Each write goes to disk! } } catch (IOException e) {} long unbuffered = System.currentTimeMillis() - start; // With buffering (fast) start = System.currentTimeMillis(); try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) { for (int i = 0; i < iterations; i++) { bw.write("A"); // Writes to buffer first } } catch (IOException e) {} long buffered = System.currentTimeMillis() - start; System.out.println("Unbuffered: " + unbuffered + "ms"); System.out.println("Buffered: " + buffered + "ms"); System.out.println("Speedup: " + (unbuffered / (double) buffered) + "x"); } }

5. The Comparison & Decision Layer

Decision Tree: Which Stream to Use?

graph TD A{What are you reading/writing?} A -- Binary data --> B[Byte Stream] A -- Text data --> C[Character Stream] B --> D{Large file?} C --> E{Large file?} D -- Yes --> F[BufferedInputStream/OutputStream] D -- No --> G[FileInputStream/OutputStream] E -- Yes --> H[BufferedReader/Writer] E -- No --> I[FileReader/Writer]

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "Why does read() return int instead of byte?" Answer: To distinguish EOF (end-of-file) from actual data!

java
// Returns int (0-255 for data, -1 for EOF) int data = inputStream.read(); if (data == -1) { // EOF reached } // If it returned byte (-128 to 127): // How would you distinguish actual byte value -1 from EOF? // You couldn't! Hence int (-1 = EOF, 0-255 = data)

Pro-Tip: Always use try-with-resources (Java 7+):

java
// ❌ OLD WAY: Manual cleanup FileInputStream fis = null; try { fis = new FileInputStream("file.txt"); // Use stream } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); // Boilerplate! } catch (IOException e) {} } } // ✅ NEW WAY: Automatic cleanup try (FileInputStream fis = new FileInputStream("file.txt")) { // Use stream } // Auto-closed here, even if exception!

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01