JavaReading & Writing Files

Reading & Writing Files

Knowing a file's path (via java.io.File, from the previous page) is only half the story — actually reading or writing its contents needs a stream. Java offers both a classic, verbose approach and much simpler modern one-liners.

Reading a File: Classic Approach

The traditional way to read a text file line by line wraps a FileReader in a BufferedReader, which adds an efficient readLine() method.

Reading with BufferedReader

Java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ClassicReadDemo {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("notes.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Could not read file: " + e.getMessage());
        }
    }
}
Reading a File: Modern One-Liners

java.nio.file.Files offers the same result with far less ceremony: Files.readAllLines(path) (Java 8+) returns every line as a List<String>, and Files.readString(path) (Java 11+) returns the entire file as a single String.

Reading with Files.readString / Files.readAllLines

Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;
import java.util.List;

public class ModernReadDemo {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("notes.txt");

        String wholeFile = Files.readString(path); // Java 11+
        System.out.println(wholeFile);

        List<String> lines = Files.readAllLines(path); // Java 8+
        System.out.println("Line count: " + lines.size());
    }
}
Tip
For typical, everyday text file tasks, prefer `Files.readString()` or `Files.readAllLines()` over hand-rolling a `BufferedReader` loop. They are shorter, harder to get wrong, and handle resource cleanup for you. Reach for the classic stream-based approach mainly when you need fine-grained control — for example, processing an enormous file one line at a time without loading it all into memory.
Writing a File: Classic vs. Modern

Writing with FileWriter/BufferedWriter

Java
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class ClassicWriteDemo {
    public static void main(String[] args) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            writer.write("Hello, file!");
            writer.newLine();
            writer.write("Second line.");
        } catch (IOException e) {
            System.out.println("Could not write file: " + e.getMessage());
        }
    }
}

Writing with Files.writeString

Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;

public class ModernWriteDemo {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("output.txt");
        Files.writeString(path, "Hello, file!" + System.lineSeparator() + "Second line.");
    }
}
Always use try-with-resources for the classic approach
`BufferedReader`, `FileReader`, `FileWriter`, and `BufferedWriter` all hold an open operating-system file handle that must be closed, even if an error occurs mid-read or mid-write. The try-with-resources syntax used above (`try (Resource r = ...) `) closes the resource automatically once the block exits, whether normally or via an exception — always prefer it over manually calling `.close()` yourself.
Warning
Nearly every file operation in Java — opening, reading, writing, even some `Files` methods — can throw `IOException`, a checked exception. The compiler forces you to either catch it (as in the examples above) or declare it with throws IOException on the enclosing method. There is no way to silently ignore the possibility of a file operation failing.
  • BufferedReader/FileReader and FileWriter/BufferedWriter are the classic, stream-based approach.

  • Files.readString()/Files.readAllLines() (reading) and Files.writeString() (writing) are much simpler modern one-liners.

  • Always wrap classic stream resources in try-with-resources so they are closed automatically.

  • IOException is checked — every file operation forces you to catch it or declare throws IOException.