I want to list all files in a directory and subdirectories within that directory that match a file mask.
For example "M:\SOURCE\*.doc" while SOURCE may look like this:
|-- SOURCE
| |-- Folder1
| | |-- File1.doc
| | |-- File1.txt
| |-- File2.doc
| |-- File3.xml
Should return File1.doc and File2.doc.
Initially, I use a DirectoryStream, because that already makes some checks for the mask/glob syntax as well as being able to use it for filtering as this ISN'T just some regex but an actual file mask that a regular user finds easier to understand
Files.newDirectoryStream(path, mask);
The problem is a DirectoryStream only checks the immediate path directory that you provide and not it's subdirectories
THEN comes a "flattening" method with Files.walk which is in fact able to look through all of the subdirectories, problem is, it DOES NOT provide with the possibility to "filter" by a File Mask the same way that a DirectoryStream does
Files.walk(path, Integer.MAX_VALUE);
So I'm stuck, unable to combine the best of both methods here...
I think I might have solved my own question with the insight received here and other questions mentioning the PathMatcher
object
final PathMatcher maskMatcher = FileSystems.getDefault()
.getPathMatcher("glob:" + mask);
final List<Path> matchedFiles = Files.walk(path)
.collect(Collectors.toList());
final List<Path> filesToRemove = new ArrayList<>(matchedFiles.size());
matchedFiles.forEach(foundPath -> {
if (!maskMatcher.matches(foundPath.getFileName()) || Files.isDirectory(foundPath)) {
filesToRemove.add(foundPath);
}
});
matchedFiles.removeAll(filesToRemove);
So basically .getPathMatcher("glob:" + mask);
is the same thing that the DirectoryStream was doing to filter the files
All I have to do now after that is filtering the list of paths that I get with Files.walk by removing the elements that do not match my PathMatcher and are not of type File