Explain Codes LogoExplain Codes Logo

Recursively list files in Java

java
file-system
performance-optimization
java-nio
Nikita BarsukovbyNikita Barsukov·Sep 6, 2024
TLDR

For a quick and concise solution, leverage the Files.walk() method from java.nio.file.

import java.nio.file.*; try (Stream<Path> paths = Files.walk(Paths.get("/your/start/dir"))) { paths.filter(Files::isRegularFile).forEach(System.out::println); }

Tip: Use try-with-resources to automatically close the stream and handle exceptions. This snippet lists all files in the directory tree. Replace /your/start/dir with your starting directory.

Better control with java.nio techniques

Performance optimization and file attribute filtering

If you need to filter files based on file attributes or improve performance, consider Files.find(). It applies a BiPredicate for efficient filtering:

import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; try (Stream<Path> stream = Files.find(Paths.get("/your/start/dir"), Integer.MAX_VALUE, (path, attr) -> attr.isRegularFile())) { // Looks like it's time to find some buried treasure. stream.forEach(System.out::println); }

Ensure you benchmark performance. Use a HashSet to avoid listing duplicate files and apply Java 8's stream operations to exit early for performance optimization.

The charm of external libraries

For a more user-friendly approach, external libraries like Apache Commons IO come into play.

import org.apache.commons.io.FileUtils; // Looks like we're on an adventure. Time to wear the Indiana Jones hat. File dir = new File("/your/start/dir"); Collection<File> files = FileUtils.listFiles(dir, null, true); for (File file : files) { System.out.println(file.getAbsolutePath()); }

FileUtils.listFiles() simplifies the task, eliminating the need to write custom file visiting logic.

Need more control? Try recursive walk method

When you need further control over file traversal, use your own recursive walk method:

// It seems we're really digging deep now. Let's turn on our headlamps. public void listFilesRecursively(File dir) { File[] files = dir.listFiles(); if (files == null || files.length == 0) return; for (File file : files) { if (file.isDirectory()) { listFilesRecursively(file); } else { System.out.println(file.getAbsolutePath()); } } }

When you need more control than Files.walk() or external utilities offer, use this approach.

Advanced use cases

Comprehensive depth-first file traversal with java.nio.file.Files.walkFileTree

For more control over directory walk, Files.walkFileTree allows a detailed depth-first file traversal:

import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; // The trove isn't going to find itself. Let's start digging Path start = Paths.get("/your/start/dir"); Files.walkFileTree(start, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { System.out.println(file.toAbsolutePath()); return FileVisitResult.CONTINUE; } });

It allows handling of specific cases like symbolic links or making decisions whether to continue or abort the walk.

Caveats to note

Always check if directories are non-null and non-empty before processing. When dealing with symbolic links or filesystem loops, Files.walk() can throw a FileSystemLoopException. Plan to handle exceptions gracefully for improved maintainability, because as the old saying goes, it's better safe than sorry.

Performance: Not to be overlooked

As file system type and size can affect performance, benchmark your implementation. Check out GitHub projects comparing various methods and choose the one that fits your needs best. Generally, java.nio comes out on top in most scenarios, but remember, the choice is yours.