Working with Advanced APIs
Java NIO.2 goes beyond basic file operations. This lesson covers
DirectoryStreamfor memory-efficient directory traversal,WatchServicefor filesystem event monitoring,BasicFileAttributesfor rich metadata access, and how to read and set file attributes and permissions — all topics that appear in OCP exam scenarios.
Files.walk vs Files.find — Revisited
Both return a lazy Stream<Path>, but they differ in how filtering works:
java// walk + filter (filtering happens after path emission)
try (Stream<Path> s = Files.walk(Path.of("/app/logs"), 3)) {
s.filter(p -> p.toString().endsWith(".log"))
.forEach(System.out::println);
}
// find — filtering happens during traversal via BiPredicate<Path, BasicFileAttributes>
try (Stream<Path> s = Files.find(
Path.of("/app/logs"),
3,
(path, attrs) -> attrs.isRegularFile()
&& attrs.size() > 1024
&& path.toString().endsWith(".log"))) {
s.forEach(System.out::println);
}Files.find is more efficient when you need to filter on file attributes (size, last-modified, type) because the attributes are fetched once per entry rather than requiring a separate Files.readAttributes() call.
DirectoryStream
Files.newDirectoryStream() returns a DirectoryStream<Path> that streams the direct children of a directory. It uses less memory than collecting all entries into a list and supports glob-pattern filtering.
java// Iterate direct children
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Path.of("/tmp"))) {
for (Path entry : ds) {
System.out.println(entry.getFileName());
}
}
// With glob filter — only .java files
try (DirectoryStream<Path> ds =
Files.newDirectoryStream(Path.of("/src"), "*.java")) {
for (Path entry : ds) {
System.out.println(entry);
}
}
// With a custom filter (DirectoryStream.Filter functional interface)
try (DirectoryStream<Path> ds = Files.newDirectoryStream(
Path.of("/tmp"),
path -> Files.isRegularFile(path) && Files.size(path) > 0)) {
for (Path entry : ds) {
System.out.println(entry);
}
}DirectoryStream does not recurse into subdirectories. Use Files.walk for recursive traversal.
BasicFileAttributes
BasicFileAttributes provides a snapshot of a file's metadata. Reading all attributes at once is more efficient than calling individual Files.isDirectory(), Files.size(), etc. methods separately.
javaPath p = Path.of("/tmp/report.pdf");
BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class);
System.out.println("Regular file : " + attrs.isRegularFile());
System.out.println("Directory : " + attrs.isDirectory());
System.out.println("Symbolic link: " + attrs.isSymbolicLink());
System.out.println("Size (bytes) : " + attrs.size());
System.out.println("Created : " + attrs.creationTime());
System.out.println("Last modified: " + attrs.lastModifiedTime());
System.out.println("Last accessed: " + attrs.lastAccessTime());FileTime objects returned by the time methods implement Comparable and have a toInstant() method for integration with java.time.
javaInstant modified = attrs.lastModifiedTime().toInstant();
boolean isRecent = modified.isAfter(Instant.now().minus(Duration.ofDays(7)));Platform-Specific Attributes
PosixFileAttributes (Unix/macOS) and DosFileAttributes (Windows) extend BasicFileAttributes with platform-specific metadata.
java// POSIX attributes — owner, group, permissions
PosixFileAttributes posix = Files.readAttributes(p, PosixFileAttributes.class);
System.out.println("Owner : " + posix.owner().getName());
System.out.println("Group : " + posix.group().getName());
System.out.println("Permissions: " + PosixFilePermissions.toString(posix.permissions()));
// e.g., "rwxr-xr--"Setting File Permissions
java// Set permissions using a PosixFilePermission set
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
Files.setPosixFilePermissions(p, perms);
// Create a file with specific permissions from the start
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(perms);
Files.createFile(Path.of("/tmp/secure.txt"), attr);PosixFilePermissions.fromString() interprets a 9-character string in rwxrwxrwx format (owner/group/others).
WatchService
WatchService monitors a directory for filesystem events without polling. It is backed by native OS mechanisms (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows).
javaPath dir = Path.of("/tmp/watched");
WatchService watcher = FileSystems.getDefault().newWatchService();
// Register events to watch
dir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
// Event loop — typically runs on a background thread
while (true) {
WatchKey key = watcher.take(); // blocks until an event occurs
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
Path filename = (Path) event.context();
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("Created: " + dir.resolve(filename));
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("Modified: " + dir.resolve(filename));
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("Deleted: " + dir.resolve(filename));
}
}
boolean valid = key.reset(); // re-register the key for future events
if (!valid) break; // directory no longer accessible
}Key points:
take()blocks;poll()returns immediately (nullif no event).- Always call
key.reset()after processing; if it returnsfalse, the key is no longer valid. WatchServicewatches only one directory level — not subdirectories.
FileAttribute Summary
| Attribute type | Platform | Access via |
|---|---|---|
BasicFileAttributes |
All | Files.readAttributes(p, BasicFileAttributes.class) |
PosixFileAttributes |
Unix/macOS | Files.readAttributes(p, PosixFileAttributes.class) |
DosFileAttributes |
Windows | Files.readAttributes(p, DosFileAttributes.class) |
Key Rules Summary
Files.findis more efficient thanFiles.walkwhen filtering on file attributes.DirectoryStreamcovers only direct children; close it with try-with-resources.BasicFileAttributesprovides a single-call metadata snapshot — prefer it over multipleFiles.*calls.WatchServiceuses native OS events;take()blocks until an event arrives.- After processing
WatchKeyevents, callreset()— afalsereturn means the directory is gone. PosixFilePermissions.fromString("rwxr-x---")converts a permission string to aSet<PosixFilePermission>.
References
- Oracle Docs — WatchService
- Oracle Docs — BasicFileAttributes
- OCP Study Guide, Chapter 14 — I/O