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…
Advertisement
Answer
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