File Handling
Files are how your programs talk to the outside world between runs. Java gives you a rich, layered set of APIs — from the battle-tested java.io.File class introduced in Java 1.0, all the way to the sleek java.nio.file package that arrived in Java 7 — so you can read configs, write logs, parse CSVs, compress archives, and much more.
Why File Handling Matters
Almost every real application touches the file system at some point: loading settings, persisting data, importing/exporting reports, or reading user-supplied content. Understanding which Java API to reach for — and why — saves you from subtle bugs and poor performance.
A Quick Tour of Java’s File APIs
Java has evolved its file handling story significantly over the decades. Here is a high-level map:
| API | Package | Introduced | Best For |
|---|---|---|---|
File | java.io | Java 1.0 | Legacy code; simple existence/metadata checks |
Stream classes (FileInputStream, FileReader, …) | java.io | Java 1.0 | Byte-by-byte or character-by-character I/O |
RandomAccessFile | java.io | Java 1.0 | Seek to arbitrary positions; binary records |
NIO.2 (Path, Files) | java.nio.file | Java 7 | Modern, concise, exception-rich file operations |
ZipInputStream / ZipOutputStream | java.util.zip | Java 1.1 | Reading and writing .zip archives |
Tip: For new code, prefer the
java.nio.file(Path/Files) API over the olderjava.io.File. It throws descriptive exceptions, supports symbolic links, and has atomic operations.
A Minimal Working Example
Before diving into the individual topics, here is a taste of how straightforward file handling can be with modern Java:
import java.nio.file.*;
public class QuickDemo {
public static void main(String[] args) throws Exception {
Path file = Path.of("greeting.txt");
// Write text to a file (creates or overwrites)
Files.writeString(file, "Hello, file system!");
// Read it back in one call
String content = Files.readString(file);
System.out.println(content);
// Delete when done
Files.delete(file);
}
}
Output:
Hello, file system!
Three lines to write, read, and delete a file — that is the power of java.nio.file.
How It Works Under the Hood
When you call any file API, Java ultimately delegates to the operating system through the JVM’s native layer (JNI). On Linux this means open(2), read(2), write(2), and close(2) system calls; on Windows it maps to CreateFile, ReadFile, etc. The JVM’s FileSystem abstraction hides those differences behind a uniform interface.
Buffering matters. Reading or writing one byte at a time causes one system call per byte — catastrophically slow for large files. Wrapping streams in BufferedInputStream / BufferedOutputStream (or using Files.readAllBytes / Files.writeString) batches I/O into chunks (typically 8 KB), cutting system-call overhead dramatically.
Character encoding. Files store bytes; String holds Unicode characters. Every time you read or write text you are implicitly applying a charset (e.g., UTF-8). If you omit the charset argument in older APIs, Java uses the platform default, which varies by OS — a classic source of encoding bugs. Always specify StandardCharsets.UTF_8 (or pass it to Files methods that accept a Charset).
File handles are OS resources. Forgetting to close a FileInputStream leaks a file descriptor. Always use try-with-resources:
try (var reader = new java.io.FileReader("data.txt")) {
// use reader
} // automatically closed here
Warning: On Windows, an unclosed file handle prevents other processes from deleting or renaming the file. On Linux the file can be deleted, but the descriptor keeps the data alive until GC — wasting disk space.
Checked vs Unchecked Exceptions
Most java.io methods throw IOException (checked), so the compiler forces you to handle it. java.nio.file methods throw subclasses like NoSuchFileException or FileAlreadyExistsException, giving you much more precise error messages. See Exception Handling for a refresher on checked exceptions.
import java.nio.file.*;
import java.io.IOException;
public class SafeRead {
public static void main(String[] args) {
try {
String text = Files.readString(Path.of("missing.txt"));
System.out.println(text);
} catch (NoSuchFileException e) {
System.out.println("File not found: " + e.getFile());
} catch (IOException e) {
System.out.println("I/O error: " + e.getMessage());
}
}
}
Output:
File not found: missing.txt
Common File Operations at a Glance
import java.nio.file.*;
public class CommonOps {
public static void main(String[] args) throws Exception {
Path p = Path.of("sample.txt");
// Check existence
System.out.println(Files.exists(p)); // false
// Create and write
Files.writeString(p, "Line 1\nLine 2\n");
// Check size
System.out.println(Files.size(p) + " bytes"); // 14 bytes
// Read all lines
Files.readAllLines(p).forEach(System.out::println);
// Rename / move
Path renamed = Path.of("renamed.txt");
Files.move(p, renamed, StandardCopyOption.REPLACE_EXISTING);
// Copy
Files.copy(renamed, Path.of("backup.txt"));
// Delete
Files.delete(renamed);
Files.delete(Path.of("backup.txt"));
}
}
Output:
false
14 bytes
Line 1
Line 2
In This Section
- File Class — The classic
java.io.FileAPI for metadata, existence checks, and directory listing. - Create a File — Multiple ways to create new files (and directories) programmatically.
- Read a File Line by Line — Efficient techniques for reading large text files one line at a time with
BufferedReaderandFiles.lines(). - Write to a File — Writing text and bytes using
FileWriter,PrintWriter, and the modernFiles.writeString(). - Delete a File — Safely deleting files and directories, including non-empty directory trees.
- RandomAccessFile — Seeking to arbitrary byte positions for reading and writing binary record-based formats.
- Create & Read Zip Files — Compressing and extracting files with
ZipOutputStreamandZipInputStream. - NIO.2: Path & Files — The modern
java.nio.fileAPI — paths, metadata, directory walking, symbolic links, andWatchService.
Related Topics
- Java I/O — The big picture of Java’s I/O streams, from bytes to characters.
- BufferedReader — Fast line-by-line text reading wrapped around any
Reader. - Serialization — Persisting entire object graphs to files as binary data.
- NIO.2: Path & Files — Modern, expressive file-system operations introduced in Java 7.
- Exception Handling — Handling
IOExceptionand its many subclasses correctly. - try-catch Block — Using try-with-resources to guarantee streams are always closed.