Skip to content

Intermediate · Lambdas, streams and files · topic 40 of 60 · 30 min

Reading and writing files

Explanation

Modern Java file I/O uses java.nio.file: Path.of("data", "orders.csv") builds a path, Files.readString / Files.readAllLines read small files, Files.writeString writes, and Files.lines streams big files line by line (close it with try-with-resources). Always specify UTF-8 where it matters and handle IOException.

Paths

java
import java.nio.file.*;

Path data = Path.of("data", "orders.csv");          // data/orders.csv (or data\orders.csv on Windows)
System.out.println(data.getFileName());              // orders.csv
System.out.println(data.toAbsolutePath());          // full path
System.out.println(Files.exists(data));             // true or false
Path backup = data.resolveSibling("orders-backup.csv");
Path.of (Java 11+) is the modern form of Paths.get.

Reading small files

java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

try {
    String all = Files.readString(data);                         // whole file as one String (UTF-8)
    List<String> lines = Files.readAllLines(data, StandardCharsets.UTF_8);
    System.out.println(lines.size() + " lines");
} catch (NoSuchFileException e) {
    System.out.println("File not found: " + e.getFile());
} catch (IOException e) {
    System.out.println("Could not read: " + e.getMessage());
}

Writing files

java
Files.createDirectories(Path.of("reports"));
Files.writeString(Path.of("reports", "summary.txt"), "Total: Rs 1350\n");          // creates or replaces
Files.writeString(Path.of("reports", "log.txt"), "run at 10:00\n",
        StandardOpenOption.CREATE, StandardOpenOption.APPEND);                       // append
Files.write(Path.of("reports", "cities.txt"), List.of("Pune", "Delhi", "Goa"));     // one line each

Big files: stream line by line

readAllLines loads the whole file into memory: fine for a few MB, bad for a 2 GB log. Files.lines returns a lazy Stream<String> that reads as you go. It holds the file open, so use try-with-resources. BufferedReader with readLine is the classic alternative.

java
try (Stream<String> lines = Files.lines(Path.of("access.log"))) {
    long serverErrors = lines.filter(l -> l.contains(" 500 ")).count();
    System.out.println("500 errors: " + serverErrors);
}

try (BufferedWriter w = Files.newBufferedWriter(Path.of("out.csv"))) {
    w.write("id,amount");
    w.newLine();
}

Parsing a CSV into records

java
record Student(String name, String city, int marks) {}

List<Student> students;
try (Stream<String> lines = Files.lines(Path.of("students.csv"))) {
    students = lines.skip(1)                                  // skip the header row
            .filter(l -> !l.isBlank())
            .map(l -> l.split(","))
            .map(p -> new Student(p[0].strip(), p[1].strip(), Integer.parseInt(p[2].strip())))
            .toList();
}
Real CSV can contain quoted commas ("Mumbai, MH"); use a CSV library (such as OpenCSV or Apache Commons CSV) for production data.

Character encodings

Text files store characters as bytes using an encoding. UTF-8 handles every language, including Hindi, Tamil and emoji. Files.readString/writeString default to UTF-8; older APIs like FileReader used the platform default, which on some Windows systems was not UTF-8 before Java 18 made UTF-8 the default. When text from other systems looks garbled ("é"), an encoding mismatch is usually the cause.

Careful: Never build file paths from user input without checking (path traversal: "../../etc/passwd"), and never swallow IOException. Also remember that Files.lines and Files.newBufferedReader must be closed; forgetting try-with-resources leaks file handles.
Think of it like this: Reading a whole file with readString is like carrying the entire newspaper bundle home at once; streaming with Files.lines is like reading it page by page as it comes off the press. For a thin newspaper either works; for a 2,000-page directory, page by page is the only sane option.
Tip: Keep file paths out of your code: pass them as command-line arguments or configuration. Your program then works on any machine.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Reading and writing files · 1/6

File I/O

In this lesson you will read and write files with java dot nio dot file.

Prefer a video by a teacher? Find free videos on “java nio files readString write lines path tutorial csv” on YouTube ↗

In real life: A daily sales report from a CSV

A chain of medical shops uploads one CSV of the day's bills per branch. A Java job reads each file with Files.lines, parses the rows into records, totals the sales per branch with groupingBy, and writes a summary file that the owner receives every morning.

java
record Bill(String branch, double amount) {}
Map<String, Double> totals;
try (Stream<String> lines = Files.lines(Path.of("bills-2026-10-19.csv"))) {
    totals = lines.skip(1)
            .map(l -> l.split(","))
            .map(p -> new Bill(p[0], Double.parseDouble(p[1])))
            .collect(Collectors.groupingBy(Bill::branch, TreeMap::new, Collectors.summingDouble(Bill::amount)));
}
StringBuilder out = new StringBuilder();
totals.forEach((b, t) -> out.append(String.format("%s,%.2f%n", b, t)));
Files.writeString(Path.of("summary-2026-10-19.csv"), out);

Practice (0/3 done)

Task 1 · Question

Which is the best choice for counting matching lines in a 3 GB log file?

Task 2 · Code · Javascript

The same CSV parsing logic in JavaScript, which runs here: write parseStudents(csvText) that skips the header line and blank lines, splits each row on commas, trims the parts and returns objects { name, city, marks } with marks as a number.

Task 3 · Practice

Write a Java program that reads students.csv (name,city,marks) with Files.lines in try-with-resources, parses it into a record Student, prints the average marks per city with groupingBy and averagingInt, and writes the result to city-averages.txt with Files.write. Handle a missing file with a friendly message.

Quick quiz

Question 1

1.Which method reads a whole small text file into one String (Java 11+)?

Question 2

2.Why must Files.lines be used with try-with-resources?

Question 3

3.Which encoding handles Hindi, Tamil and English together?

Question 4

4.Files.writeString(path, text) on an existing file, with no options…

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which method reads a whole small text file into one String (Java 11+)?

Answer: Files.readString

Files.readString reads the full content as UTF-8 by default.

Why must Files.lines be used with try-with-resources?

Answer: It keeps the file open until the stream is closed

The stream holds a file handle.

Which encoding handles Hindi, Tamil and English together?

Answer: UTF-8

UTF-8 covers all Unicode characters.

Files.writeString(path, text) on an existing file, with no options…

Answer: Replaces the content

The default options create or truncate; use APPEND to add.

What does csv.DictReader give you for each row?Related

Answer: A dict with the header names as keys

DictReader uses the header row as keys, so you can write row["marks"].

From CSV files and simple statistics

Why not read CSV lines with line.split(",")?Related

Answer: Quoted values that contain commas, like "Mumbai, MH", get broken into two columns

The csv module understands quotes; a plain split does not.

From Reading CSV and JSON with the standard library

Which mode adds new text to the end of a file and keeps the old text?Related

Answer: "a"

"a" means append: new text goes after what is already there.

From Working with files

Why use a stream for a 5 GB log file?Related

Answer: It processes chunks without loading the whole file into memory

Streams keep memory use small.

From Files and a tiny server in Node

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Lambdas, streams and files”. The module exam comes next.
  2. Module 8 exam: Lambdas, streams and files · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Multithreading and concurrency. 60 topics left in the course before the final exam.

← Previous: Collectors: grouping and summarising