TL;DR: if you you need to filter out files/dirs by attributes - use Files.find()
, if you don't need to filter by file attributes - use Files.walk()
.
Details
There is a slight difference which is actually explained in the documentation, but in a way that it feels completely wrong. Reading the source code makes it clear:
Files.find:
return StreamSupport.stream(...)
.onClose(iterator::close)
.filter(entry -> matcher.test(entry.file(), entry.attributes()))
.map(entry -> entry.file());
Files.walk:
return StreamSupport.stream(...)
.onClose(iterator::close)
.map(entry -> entry.file());
This means that if, in your eventual filter, you need to get and validate file attributes - chances are that File.find
will be faster. That's because with File.walk
, your filter callback will need an extra call to e.g. Files.readAttributes(file, BasicFileAttributes.class)
, while with File.find
- the attributes are already retrieved and given to you in the filter callback.
I just tested it with my sample 10K-files-in-many-folders structure on Windows, by searching files only (i.e. excluding folders):
// pre-Java7/8 way via recursive listFiles (8037 files returned): 1521.657 msec.
for (File f : new File(dir).listFiles()) {
if (f.isDirectory()) {
_getFiles(files, path, pattern);
} else {
...
}
}
// Files.walk(8037 files returned): 1575.766823 msec.
try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE) {
files = stream.filter(p -> {
if (Files.isDirectory(p)) { return false; } // this extra check makes it much slower than Files.find
...
}).map(p -> p.toString()).collect(Collectors.toList());
}
// Files.find(8037 files returned): 27.606675 msec.
try (Stream<Path> stream = Files.find(path, Integer.MAX_VALUE, (p, a) -> !a.isDirectory())) {
files = stream.filter(p -> { ... }).map(p -> p.toString()).collect(Collectors.toList());
}
// Files.walkFileTree(8037 returned): 27.443974 msec.
Files.walkFileTree(new File(path).toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) throws IOException {
...
return FileVisitResult.CONTINUE;
}
});
find
is better thanwalk
if you’re only planning to apply a filter to the Stream returned bywalk
. – Heikeheil