Java File I/O — Introduction
Almost every real-world Java application needs to read from or write to files — configuration files, logs, CSV data exports, JSON API responses, or user uploads. Java provides two main packages for file I/O: the classic java.io (since Java 1.0) and the modern java.nio.file (since Java 7).
In this chapter, you’ll learn the landscape of Java I/O, understand the key abstractions, and know when to use which approach.
java.io vs java.nio
| Feature | java.io (classic) |
java.nio.file (modern) |
|---|---|---|
| Introduced | Java 1.0 (1996) | Java 7 (2011) |
| API style | Stream-based (InputStream, OutputStream) |
Path-based (Path, Files) |
| Blocking? | Yes (blocking I/O) | Supports non-blocking (NIO channels) |
| File operations | Basic (read, write, delete) | Rich (walk, find, copy, move, watch) |
| Recommendation | Use for legacy code | Use for all new code |
Rule of thumb: Use
java.nio.file.Filesandjava.nio.file.Pathfor all new file operations. Fall back tojava.ioonly when a library requires it.
Byte Streams vs Character Streams
Java distinguishes between binary data (bytes) and text data (characters):
| Byte Streams | Character Streams | |
|---|---|---|
| Base classes | InputStream / OutputStream |
Reader / Writer |
| Unit | byte (8 bits) |
char (16 bits, Unicode) |
| Use for | Images, PDFs, binary files | Text files, CSV, JSON, XML |
| Examples | FileInputStream, BufferedInputStream |
FileReader, BufferedReader |
Always Close Your Resources
File handles are limited system resources. Always close them after use. The modern way is try-with-resources:
// ✅ Good — automatically closes the reader
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// reader is automatically closed here, even if an exception occurs
What’s Next?
In the next chapter, you’ll learn how to read files using both classic BufferedReader and modern Files.readString().