Lesson 33 • Advanced
IO & NIO
Every real application reads and writes data. Java offers two approaches: the classic IO library (stream-based, simple) and the modern NIO.2 API (buffer-based, powerful). Knowing when to use each is the mark of a skilled developer.
Before You Start
You should know Exception Handling (try-with-resources) and Streams API (since NIO.2 returns Stream<Path>). Basic understanding of byte vs character data helps.
What You'll Learn
- ✅ InputStream/OutputStream vs Reader/Writer
- ✅ BufferedReader and try-with-resources
- ✅ NIO.2: Path, Files, and FileChannel
- ✅ Watching directories with WatchService
- ✅ Memory-mapped files for performance
- ✅ Choosing between IO and NIO
1️⃣ IO vs NIO — When to Use Which
Analogy: Classic IO is like drinking through a straw — data flows one direction, one byte at a time. NIO is like a bucket brigade — you fill buffers, pass them through channels, and can even read and write simultaneously.
| Feature | IO (java.io) | NIO (java.nio) |
|---|---|---|
| Model | Stream-based (byte by byte) | Buffer + Channel (block-based) |
| Blocking | Always blocking | Non-blocking possible (Selectors) |
| Direction | One-way (in or out) | Bidirectional channels |
| Best for | Simple reads/writes | High-performance, large files |
Try It: Classic IO File Operations
// 💡 Try modifying this code and see what happens!
// Simulating Java Classic IO operations
console.log("=== Classic IO File Operations ===\n");
// Simulate a file system in memory
const fileSystem = new Map();
// Writing to a file (FileWriter + BufferedWriter)
function writeFile(path, content) {
fileSystem.set(path, content);
return content.length;
}
// Reading a file (FileReader + BufferedReader)
function readFile(path) {
if (!fileSystem.has(path)) throw new Error("FileNotFoundExcep
...2️⃣ NIO.2 — The Modern Approach
For most file operations, the NIO.2 Files utility class (Java 7+) is the best starting point. It wraps complex channel operations into simple one-liners. Use Path instead of the legacy File class everywhere.
Files.readString(path) — Java 11+, read entire small file
Files.lines(path) — lazy Stream for large files
Files.walk(dir) — recursive directory traversal
Files.copy(src, dst) — efficient file copying
Try It: NIO.2 Path & Files API
// 💡 Try modifying this code and see what happens!
// Simulating Java NIO.2 Path and Files operations
console.log("=== NIO.2 Path & Files API ===\n");
// Simulated file system with Path-like API
const fs = new Map();
fs.set("/project/src/Main.java", "public class Main {}");
fs.set("/project/src/Utils.java", "public class Utils {}");
fs.set("/project/src/test/TestMain.java", "class TestMain {}");
fs.set("/project/README.md", "# My Project");
fs.set("/project/pom.xml", "<project>...</project>")
...Common Mistakes
- ⚠️ Not closing resources: Always use try-with-resources. Unclosed streams leak file handles and can crash your OS
- ⚠️ Reading entire large files into memory: Use
Files.lines()(returns lazy Stream) instead ofreadAllLines()for GB-sized files - ⚠️ Using java.io.File in new code: It's legacy. Use
PathandFilesfrom java.nio.file - ⚠️ Forgetting character encoding: Always specify
StandardCharsets.UTF_8— the default varies by OS!
Pro Tips
- 💡
Files.readString(path)(Java 11+) — one-liner to read an entire small file - 💡
Files.walk(dir)returns aStream<Path>— combine with filter/map for elegant directory traversal - 💡 Memory-mapped files (
FileChannel.map()) give you the fastest I/O for large files — the OS handles caching - 💡
WatchServicelets you monitor directories for changes — essential for hot-reload features
Try It: FileChannel & WatchService
// 💡 Try modifying this code and see what happens!
// Simulating FileChannel operations and WatchService
console.log("=== FileChannel & WatchService ===\n");
// 1. FileChannel — buffer-based I/O
console.log("1. FILECHANNEL (buffer-based):");
let buffer = new ArrayBuffer(1024);
let view = new Uint8Array(buffer);
let message = "Hello, NIO!";
for (let i = 0; i < message.length; i++) view[i] = message.charCodeAt(i);
console.log(" Allocated ByteBuffer(1024)");
console.log(" Written: \"" + messag
...📋 Quick Reference
| Task | API | Notes |
|---|---|---|
| Read file | Files.readString(path) | Java 11+, small files |
| Write file | Files.writeString(path, s) | Creates or overwrites |
| Stream lines | Files.lines(path) | Lazy, memory-efficient |
| Walk tree | Files.walk(dir) | Returns Stream<Path> |
| Fast copy | FileChannel.transferTo() | Zero-copy for large files |
🎉 Lesson Complete!
You've mastered Java IO & NIO — from simple file reads to high-performance channels! Next: JDBC — connecting Java to databases.
Sign up for free to track which lessons you've completed and get learning reminders.