File I/O in Java: Reading and Writing Files the Modern Way
Learn file input/output in Java with the modern Files and Path API — read and write text, handle IOException, and use try-with-resources to close files safely.
Programs become far more useful when they can remember things between runs — save a report, read a config file, log what happened. That means working with files. In this lesson you'll learn the modern, clean way to read and write files in Java, plus the one safety habit that prevents a whole class of bugs. It's more practical than intimidating, promise.
Reading and writing: the modern way
Older Java file code was verbose and fiddly. Modern Java (via the java.nio.file package) makes the common cases wonderfully short. Meet Files and Path:
Writing a file
import java.nio.file.*; Path path = Path.of("notes.txt"); Files.writeString(path, "Hello from Java!\nSecond line."); // done — file written
Reading a file
// whole file as one String String content = Files.readString(Path.of("notes.txt")); System.out.println(content); // or line by line into a List List<String> lines = Files.readAllLines(Path.of("notes.txt")); for (String line : lines) { System.out.println(line); }
That's genuinely all you need for most everyday file work. Files.writeString, Files.readString, and Files.readAllLines cover a huge amount of ground.
Files operations are "checked" — you must handle IOException
Remember checked exceptions from the exceptions lesson? File operations can fail for reasons outside your control — the file might be missing, locked, or the disk full — so Java forces you to handle an IOException. Wrap file code in a try-catch:
try { String content = Files.readString(Path.of("notes.txt")); System.out.println(content); } catch (IOException e) { System.out.println("Could not read the file: " + e.getMessage()); }
Reading larger files with a reader
For big files you don't want to load entirely into memory. A BufferedReader reads line by line efficiently — and here's where the safety habit comes in:
// try-with-resources: the reader is closed for you automatically try (BufferedReader reader = Files.newBufferedReader(Path.of("big.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
try (...). Files, readers, and database connections must be closed when you're done, or you'll leak resources. Try-with-resources closes them automatically — even if an exception occurs. Always open files this way and you'll never forget to close one. This is the modern replacement for manually calling .close() in a finally block.Checking and creating files
The Files class has handy helpers for common checks:
Path p = Path.of("data.txt"); Files.exists(p); // true/false Files.createFile(p); // create a new empty file Files.createDirectories(Path.of("logs/2026")); // make folders Files.delete(p); // delete it
File I/O is one of those skills you reach for constantly once you know it — reading a config, exporting a report, appending to a log. The habit I'd most urge you to lock in early is try-with-resources: I've debugged real problems caused by files and connections left open, and this single pattern makes that mistake impossible. Learn the short Files methods for the easy cases and always open resources in a try (...), and you've got file handling covered.
Key takeaways
- Modern file I/O uses
Files+Path:writeString,readString,readAllLines. - File operations throw checked
IOException— you musttry-catchthem. - Always use try-with-resources (
try (Reader r = ...)) so files/streams close automatically. Filesalso offersexists,createFile,createDirectories,delete.
← Previous: Lesson 30 — Multithreading in Java
Next: Lesson 32 — Date & Time API →