Files and Date-Time · Lesson 37 of 42
File Handling with java.nio.file
Programs need to keep data after they stop: reports, logs, exports, configuration. Modern Java handles files with the java.nio.file package – Path for locations and Files for operations. It is shorter and safer than the old FileReader/FileWriter code you will still see in older tutorials.
In this lesson
PathandFiles: the modern API- Writing and reading whole files and line by line
- Directories, checks, copying and deleting
- A real task: summarising a CSV file
Write and read a file
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.writeString(file, "Day 1: installed the JDK\nDay 2: variables\n"); // create / overwrite
Files.writeString(file, "Day 3: loops\n", java.nio.file.StandardOpenOption.APPEND);
String all = Files.readString(file);
System.out.print(all);
List<String> lines = Files.readAllLines(file);
System.out.println(lines.size() + " lines, first: " + lines.get(0));
System.out.println(Files.exists(file) + " " + Files.size(file) + " bytes");
}
}
Day 1: installed the JDK Day 2: variables Day 3: loops 3 lines, first: Day 1: installed the JDK true 55 bytes
- File operations throw
IOException(a checked exception), so methods must catch or declare it. Heremaindeclaresthrows IOExceptionto keep the example short. writeStringandreadStringuse UTF-8 by default – ₹, é and Indian scripts work correctly.- A relative path like
"notes.txt"is resolved against the folder you ran the program from.
Large files: read line by line
readAllLines loads the entire file into memory. For big logs, stream the lines so only a little is in memory at once:
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws IOException {
Path log = Path.of("server.log");
Files.writeString(log, "INFO start\nERROR db timeout\nINFO login asha\nERROR payment failed\nWARN disk 85%\n");
try (Stream<String> lines = Files.lines(log)) { // closed automatically
System.out.println(lines.filter(l -> l.startsWith("ERROR")).count() + " errors");
}
try (BufferedReader reader = Files.newBufferedReader(log)) { // classic loop style
String line;
int n = 0;
while ((line = reader.readLine()) != null) {
n++;
if (line.startsWith("WARN")) System.out.println("line " + n + ": " + line);
}
}
}
}
2 errors line 5: WARN disk 85%
Common mistake: not closing file streams
Files.lines(...) and newBufferedReader(...) hold an open file handle. Always use them in try-with-resources; otherwise long-running servers eventually fail with "too many open files".
Writing many lines
import java.io.BufferedWriter;
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 {
List<String> tasks = List.of("buy milk", "call bank", "finish chapter 14");
Path todo = Path.of("todo.txt");
Files.write(todo, tasks); // one element per line
try (BufferedWriter w = Files.newBufferedWriter(Path.of("report.txt"))) {
for (int i = 0; i < tasks.size(); i++) {
w.write((i + 1) + ". " + tasks.get(i));
w.newLine();
}
}
System.out.print(Files.readString(Path.of("report.txt")));
}
}
1. buy milk 2. call bank 3. finish chapter 14
Directories and file operations
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws IOException {
Path dir = Path.of("exports", "2026");
Files.createDirectories(dir); // creates parents too
Path a = dir.resolve("sales.csv"); // exports/2026/sales.csv
Files.writeString(a, "id,amount\n1,500\n");
Path b = dir.resolve("sales-backup.csv");
Files.copy(a, b, StandardCopyOption.REPLACE_EXISTING);
System.out.println(a.getFileName() + " | parent: " + a.getParent());
try (Stream<Path> files = Files.list(dir)) {
files.map(p -> p.getFileName().toString()).sorted().forEach(System.out::println);
}
Files.delete(b);
System.out.println(Files.exists(b));
}
}
sales.csv | parent: exports/2026 sales-backup.csv sales.csv false
On Windows the parent prints as exports\2026; Path uses the right separator for each system, so never hard-code "/" or "\\" when building paths – use Path.of(a, b) or resolve.
A real task: summarise a CSV
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) throws IOException {
Path csv = Path.of("sales.csv");
Files.writeString(csv, """
region,rep,amount
North,Asha,1200
South,Ben,800
North,Chen,450
South,Dia,1500
East,Eli,not-a-number
""");
Map<String, Integer> totals = new TreeMap<>();
List<String> lines = Files.readAllLines(csv);
for (String line : lines.subList(1, lines.size())) { // skip the header
String[] f = line.split(",");
try {
totals.merge(f[0], Integer.parseInt(f[2]), Integer::sum);
} catch (NumberFormatException e) {
System.out.println("Skipped bad row: " + line);
}
}
System.out.println(totals);
System.out.println("Grand total: " + totals.values().stream().mapToInt(Integer::intValue).sum());
}
}
Skipped bad row: East,Eli,not-a-number
{North=1650, South=2300}
Grand total: 3950For real CSV files – with quoted commas, for example – use a library such as OpenCSV or Apache Commons CSV. For JSON, Spring Boot uses Jackson.
Practice
Try it yourself
Write the numbers 1–5 to
numbers.txt, then read them back and print their sum.Show solution
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 p = Path.of("numbers.txt"); Files.write(p, List.of("1", "2", "3", "4", "5")); int sum = Files.readAllLines(p).stream().mapToInt(Integer::parseInt).sum(); System.out.println(sum); } }15
Quick check
Which exception do most file methods throw?
IOException – a checked exception.
Why use Files.lines instead of readAllLines for a 5 GB log?
It streams lines lazily instead of loading the whole file into memory.
How do you build "exports/2026/sales.csv" portably?
Path.of("exports", "2026", "sales.csv") or dir.resolve("sales.csv").
Summary
- Use
Pathfor locations andFilesfor operations; they default to UTF-8. - readString/readAllLines for small files; Files.lines or BufferedReader in try-with-resources for big ones.
- createDirectories, resolve, copy, list and delete cover everyday file management.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.