Files (NIO)
Files (java.nio.file) is the modern Java I/O API: Path objects, atomic moves, walking trees, reading lines as a Stream. Use it for any file work you would have written with FileInputStream in 2010 — cleaner, faster, and harder to leak handles.
Read, write, walk, watch, atomic move
EXAMPLE
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.*;
import java.util.stream.*;
public class FilesDemo {
public static void main(String[] args) throws Exception {
// 1) Path basics
Path home = Paths.get(System.getProperty("user.home"));
Path data = home.resolve("shop").resolve("data");
Path out = data.resolve("orders.csv");
Files.createDirectories(data); // mkdir -p
// 2) Read / write — small files
Files.writeString(out, "id,total\n1,100\n", StandardCharsets.UTF_8);
String body = Files.readString(out);
List<String> lines = Files.readAllLines(out);
// 3) Stream large files line-by-line — close in try-with-resources
try (Stream<String> stream = Files.lines(out)) {
long count = stream.skip(1).count();
System.out.println("rows: " + count);
}
// 4) Atomic rename — write to .tmp, then move
Path tmp = out.resolveSibling(out.getFileName() + ".tmp");
Files.writeString(tmp, "id,total\n1,100\n2,200\n");
Files.move(tmp, out, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
// 5) Walk a directory tree
try (Stream<Path> walk = Files.walk(data)) {
walk.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".csv"))
.forEach(System.out::println);
}
// 6) Find recently modified files
try (Stream<Path> walk = Files.walk(data)) {
walk.filter(Files::isRegularFile)
.sorted(Comparator.comparing(p -> {
try { return Files.getLastModifiedTime(p).toInstant(); }
catch (IOException e) { return java.time.Instant.EPOCH; }
}, Comparator.reverseOrder()))
.limit(10)
.forEach(System.out::println);
}
// 7) Watch a directory for changes
WatchService watcher = FileSystems.getDefault().newWatchService();
data.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY);
new Thread(() -> {
while (true) {
try {
WatchKey key = watcher.take(); // blocks
for (WatchEvent<?> e : key.pollEvents()) {
System.out.println(e.kind() + " " + e.context());
}
key.reset();
} catch (InterruptedException ex) { return; }
}
}, "watcher").start();
// 8) Copy + delete recursively
Path target = data.resolveSibling("data-backup");
try (Stream<Path> walk = Files.walk(data)) {
walk.forEach(src -> {
try {
Path rel = data.relativize(src);
Path dst = target.resolve(rel);
if (Files.isDirectory(src)) Files.createDirectories(dst);
else Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) { throw new UncheckedIOException(e); }
});
}
try (Stream<Path> walk = Files.walk(target)) {
walk.sorted(Comparator.reverseOrder()).forEach(p -> {
try { Files.delete(p); }
catch (IOException e) { throw new UncheckedIOException(e); }
});
}
// 9) File attributes
BasicFileAttributes attrs = Files.readAttributes(out, BasicFileAttributes.class);
System.out.println("size: " + attrs.size());
System.out.println("created: " + attrs.creationTime());
// 10) Streams + paths together — count lines across all CSVs
try (Stream<Path> walk = Files.walk(data)) {
long total = walk
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".csv"))
.mapToLong(p -> {
try (Stream<String> ls = Files.lines(p)) { return ls.count(); }
catch (IOException e) { return 0; }
})
.sum();
System.out.println("total lines: " + total);
}
// 11) Pitfalls
// - Forgetting to close Files.lines() / Files.walk() (keep file handles)
// - Files.move() across filesystems may fail; use COPY + DELETE for cross-fs
// - ATOMIC_MOVE not supported on every filesystem; fall back gracefully
// - readAllBytes on a 10GB file -> OOM; stream instead
// - Charset omitted -> system default; ALWAYS pass UTF_8 explicitly
}
}
Why it matters
Always close `Files.lines()` and `Files.walk()` with try-with-resources. They hold OS file handles until closed, and the JVM does not eagerly reclaim them. The Streams iterator pattern looks lazy and clean, but the lazy resource is real — leak enough of them and `ulimit -n` becomes your bug.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import java.nio.file.*;
List<String> lines = Files.readAllLines(Path.of("input.txt"));
Files.writeString(Path.of("out.txt"), "hi");
Try it Yourself »
Discussion
Loading…