Java File Handling

Read and write text files with java.nio.file: Path, Files.readString, readAllLines, writeString, appending, streaming large files and handling IOException.

Lesson 76 of 127Intermediate18 min read

Programs that forget everything when they close have limited uses. Saving a game, keeping a log of what happened, loading settings, importing a spreadsheet exported as CSV, or writing a report for someone to open later: all of these need files.

Modern Java handles files with the java.nio.file package, built around two classes. Path represents the location of a file or folder, and Files has static methods to read, write, copy, move and inspect them. For most everyday tasks, a single method call is enough.

In this lesson you'll read and write whole files, append to a log, process a big file line by line without loading it all into memory, parse CSV data into objects, and deal with the IOException that every file operation can throw, because files can always be missing, locked or unreadable.

Paths

Java
import java.nio.file.Path;

Path notes = Path.of("notes.txt");               // relative to where the program runs
Path report = Path.of("reports", "2024", "july.csv");
System.out.println(report.getFileName());        // july.csv
  • Path.of() builds a path from one or more parts, using the right separator for the operating system.
  • A relative path like notes.txt is found from the folder where the program was started.
  • An absolute path starts from the top of the drive, such as C:\data\notes.txt or /home/sam/notes.txt. Avoid hard-coding these, because they won't exist on other computers.

Reading and writing whole files

TaskMethod
Read all textFiles.readString(path)
Read as a list of linesFiles.readAllLines(path)
Write text (replacing the file)Files.writeString(path, text)
Write a list of linesFiles.write(path, lines)
Add to the endFiles.writeString(path, text, StandardOpenOption.CREATE, StandardOpenOption.APPEND)

Writing replaces the file's contents unless you pass APPEND. These methods use UTF-8 by default, which handles every language's characters. They're perfect for small and medium files; for very large ones, read line by line instead.

Large files, readers and writers

Files.lines(path) returns a stream of lines that are read only as needed, so even a huge log file uses little memory. Because it holds the file open, use it in try-with-resources, which closes the file automatically:

Java
try (Stream<String> lines = Files.lines(Path.of("server.log"))) {
    long errors = lines.filter(l -> l.contains("ERROR")).count();
}

Files.newBufferedReader(path) and Files.newBufferedWriter(path) give you a reader with readLine() and a writer with write() and newLine(), for when you want full control. They also belong in try-with-resources.

Checking files and handling errors

  • Files.exists(path) and Files.isDirectory(path) check what's there.
  • Files.createDirectories(path) creates a folder and any missing parents.
  • Files.size(path), Files.copy(a, b), Files.move(a, b) and Files.delete(path) do what they say.

Almost every Files method throws IOException, a checked exception: Java makes you either catch it or declare throws IOException. A missing file throws NoSuchFileException, a subclass of IOException, so you can give a clear message.

Listing and walking folders

To see what's inside a folder, Files.list(folder) gives a stream of the paths directly inside it, and Files.walk(folder) also goes into every subfolder. Both hold the folder open, so use them in try-with-resources:

Java
try (Stream<Path> files = Files.list(Path.of("reports"))) {
    List<Path> csvFiles = files
        .filter(p -> p.toString().endsWith(".csv"))
        .sorted()
        .toList();
    System.out.println(csvFiles);
}

This pattern, list the files, keep the ones you want and process each in turn, is the basis of many batch jobs, such as importing every CSV file that arrived overnight.

Text encodings

A file stores bytes, not characters. An encoding decides how characters such as é, £ or 日 become bytes. The Files methods use UTF-8 by default, which can represent every character and is the standard on the web. If you read a file written in a different encoding, accented letters turn into odd symbols. Pass the encoding explicitly when you know it: Files.readString(path, StandardCharsets.ISO_8859_1). Since Java 18, the older FileReader and FileWriter classes also default to UTF-8 rather than the operating system's setting.

Java Files Syntax

File essentials

import java.nio.file.*;
Path p = Path.of("folder", "file.txt");
String all = Files.readString(p);
List<String> lines = Files.readAllLines(p);
Files.writeString(p, "text");
Files.writeString(p, "more\n", StandardOpenOption.CREATE, StandardOpenOption.APPEND);
try (Stream<String> s = Files.lines(p)) { ... }
Files.exists(p);  Files.createDirectories(dir);

Java Files Summary

  • Path.of(...) represents a file location; Files has static methods to work with it.
  • readString and readAllLines read whole files; writeString and write create or replace them.
  • Pass StandardOpenOption.APPEND to add to a file instead of replacing it.
  • Use Files.lines or a BufferedReader in try-with-resources for large files.
  • File methods throw the checked IOException, so catch it or declare it.

Java Files Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Saving and loading notes

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

public class Main {
    public static void main(String[] args) throws IOException {
        Path file = Path.of("notes.txt");
        Files.write(file, List.of("Buy milk", "Call Sam", "Book dentist"));

        List<String> notes = Files.readAllLines(file);
        System.out.println("You have " + notes.size() + " notes:");
        for (int i = 0; i < notes.size(); i++) {
            System.out.println((i + 1) + ". " + notes.get(i));
        }
        System.out.println("Saved? " + Files.exists(file));
    }
}
Output
You have 3 notes:
1. Buy milk
2. Call Sam
3. Book dentist
Saved? true
Line-by-line explanation
  1. Line 7Declaring throws IOException passes any file error up and stops the program with a message.
  2. Line 9write creates the file, or replaces it, with one line per item.
  3. Line 11readAllLines gives back a List with one String per line.
  4. Line 16Files.exists confirms the file is really on disk.
Example 2

Appending to a log and counting errors

Java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.stream.Stream;

public class Main {
    static void log(Path file, String message) throws IOException {
        Files.writeString(file, message + "\n",
                StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }

    public static void main(String[] args) throws IOException {
        Path file = Path.of("app.log");
        Files.deleteIfExists(file);
        log(file, "INFO Started");
        log(file, "ERROR Payment timeout");
        log(file, "INFO Order 1042 saved");
        log(file, "ERROR Disk nearly full");

        try (Stream<String> lines = Files.lines(file)) {
            lines.filter(line -> line.startsWith("ERROR"))
                 .forEach(System.out::println);
        }
    }
}
Output
ERROR Payment timeout
ERROR Disk nearly full
Line-by-line explanation
  1. Lines 9 to 10CREATE makes the file if it's missing, and APPEND adds to the end instead of replacing it.
  2. Line 15Start fresh each time the example runs.
  3. Lines 21 to 24Files.lines reads lazily, and try-with-resources closes the file afterwards.
Example 3

Reading a CSV file into records

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

public class Main {
    record Product(String name, double price, int stock) {}

    public static void main(String[] args) {
        Path csv = Path.of("products.csv");
        try {
            Files.writeString(csv, "name,price,stock\nPen,1.20,300\nBackpack,34.99,15\nLamp,24.50,22\n");

            List<Product> products = new ArrayList<>();
            for (String line : Files.readAllLines(csv).subList(1, 4)) {
                String[] parts = line.split(",");
                products.add(new Product(parts[0], Double.parseDouble(parts[1]),
                                         Integer.parseInt(parts[2])));
            }
            double value = 0;
            for (Product p : products) {
                value += p.price() * p.stock();
            }
            System.out.printf("%d products, stock worth £%.2f%n", products.size(), value);

            Files.readString(Path.of("missing.csv"));
        } catch (NoSuchFileException e) {
            System.out.println("File not found: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("Couldn't read the file: " + e.getMessage());
        }
    }
}
Output
3 products, stock worth £1423.85
File not found: missing.csv
Line-by-line explanation
  1. Line 14Create a small CSV file to read. In real use, it would come from a spreadsheet.
  2. Line 17subList(1, 4) skips the header row.
  3. Lines 18 to 20Split each line on commas and convert the text into numbers.
  4. Line 28Reading a file that doesn't exist throws NoSuchFileException.
  5. Lines 29 to 33Catch the specific exception first, then the general IOException.

Common Java Files Mistakes

Overwriting when you meant to append

Don't
Files.writeString(log, "New entry\n");     // previous entries are gone
Do
Files.writeString(log, "New entry\n", StandardOpenOption.CREATE, StandardOpenOption.APPEND);

Leaving Files.lines open

Don't
long count = Files.lines(path).count();     // file stays open
Do
try (Stream<String> lines = Files.lines(path)) {
    long count = lines.count();
}

Hard-coded absolute paths

Don't
Path p = Path.of("C:\\Users\\sam\\Desktop\\data.csv");
Do
Path p = Path.of("data", "data.csv");       // relative to the program's folder

Java Files in Real Projects

Files in real applications

Servers write log files line by line and rotate them each day, desktop applications save documents and settings, data tools import CSV exports from spreadsheets and banks, and build tools read configuration files. Larger systems move to databases, but files remain the simplest way to save data and exchange it with other programs.

Java Files FAQ

Where does Java look for a relative file path?

In the working directory: the folder the program was started from, not the folder containing the .java file. IDEs usually start programs in the project's root folder. Print Path.of("").toAbsolutePath() to see the folder your program is actually using.

What is the difference between File and Path in Java?

java.io.File is the original class from Java 1.0. Path, used with the Files class, arrived in Java 7 and has clearer methods and better error messages. Prefer Path in new code. When an older library needs a File, convert with path.toFile(), and convert back with file.toPath().

How do I read a file line by line in Java?

For small files, Files.readAllLines(path) returns a list of lines. For large files, use Files.lines(path) in try-with-resources, or a BufferedReader from Files.newBufferedReader(path) with a while ((line = reader.readLine()) != null) loop. Both read one line at a time without loading the whole file.

Should I check that a file exists before reading it?

It's often better simply to read it and catch NoSuchFileException. Between a check and the read, another program could delete or create the file, so the check doesn't guarantee anything. Files.exists is still useful to decide, for example, whether to create a default settings file.

How do I read a file packaged inside my JAR?

Files bundled with your program, such as src/main/resources/config.json, aren't ordinary files once packaged. Read them with getClass().getResourceAsStream("/config.json"), which returns an InputStream, or with getResource for a URL. Path.of only works for files on the disk.

Java Files Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the line that reads a whole file into one String.

String text = Files.(Path.of("story.txt"));
Multiple choiceeasy

What happens to a file's contents when you call Files.writeString(path, "hi")?

Multiple choicemedium

Which is best for counting lines in a 5 GB log file?

Multiple choicemedium

What kind of exception is IOException?

Predict the outputhard

A file contains three lines. What does Files.readAllLines(p).get(3) do?

Java Files Quiz

5 questions to check what you learned.

  1. Which class represents a file's location?

    • File
    • Folder
    • Path
    • Location
  2. What does try-with-resources do?

    • Closes the resource automatically, even if an exception happens
    • Retries an operation
    • Opens several files at once
    • Hides exceptions
  3. Which exception means the file wasn't found?

    • FileMissingError
    • NoSuchFileException
    • NullPointerException
    • EOFException
  4. What does Files.createDirectories(Path.of("a", "b")) do?

    • Creates a file called b
    • Deletes the folders
    • Lists the folders
    • Creates folder a and folder b inside it, if they're missing
  5. Why avoid hard-coding a path like C:\Users\sam\data.csv?

    • Backslashes aren't allowed
    • Java can't read the C drive
    • That location won't exist on other people's computers or servers
    • Absolute paths are slower