javadesign-patternsdirectory-walk

Java library to return a List<File> for glob or Ant-like pattern "*foo/**/*.txt"?


I'm looking for a lib which would provide a method which would give me a list of files matching given Ant-like pattern.

For *foo/**/*.txt I'd get

foo/x.txt
foo/bar/baz/.txt
myfoo/baz/boo/bar.txt

etc. I know it's achievable with DirWalker and

PathMatcher mat = FileSystems.getDefault().getPathMatcher("glob:" + filesPattern);

, but I'd rather some maintained lib. I expected Commons IO to have it but no.

Update: I'm happy with reusing Ant's code, but would prefer something smaller than whole Ant.


Solution

  • So I sacrified few MB of app's size for the sake of speed and used Ant's DirectoryScanner in the end.

    Also, there's Spring's PathMatchingResourcePatternResolver.

    //files = new PatternDirWalker( filesPattern ).list( baseDir );
    files = new DirScanner( filesPattern ).list( baseDir );
    
    
    public class DirScanner {
    
        private String pattern;
    
        public DirScanner( String pattern ) {
            this.pattern = pattern;
        }
    
        public List<File> list( File dirToScan ) throws IOException {
    
                DirectoryScanner ds = new DirectoryScanner();
                String[] includes = {  this.pattern };
                //String[] excludes = {"modules\\*\\**"};
                ds.setIncludes(includes);
                //ds.setExcludes(excludes);
                ds.setBasedir( dirToScan );
                //ds.setCaseSensitive(true);
                ds.scan();
    
                String[] matches = ds.getIncludedFiles();
                List<File> files = new ArrayList(matches.length);
                for (int i = 0; i < matches.length; i++) {
                    files.add( new File(matches[i]) );
                }
                return files;
        }
    
    }// class
    

    And here's my impl I started to code, not finished, just if someone would like to finish it. The idea was it would keep a stack of patterns, traverse the dir tree and compare the contents to the actual stack depth and the rest of it in case of **.

    But I resorted to PathMatcher and then to Ant's impl.

    public class PatternDirWalker {
        //private static final Logger log = LoggerFactory.getLogger( PatternDirWalker.class );
    
        private String pattern;
        private List segments;
        private PathMatcher mat;
    
        public PatternDirWalker( String pattern ) {
            this.pattern = pattern;
            this.segments = parseSegments(pattern);
            this.mat = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
        }
    
        public List<File> list( File dirToScan ) throws IOException{
    
            return new DirectoryWalker() {
                List<File> files = new LinkedList();
    
                @Override protected void handleFile( File file, int depth, Collection results ) throws IOException {
                    if( PatternDirWalker.this.mat.matches( file.toPath()) )
                        results.add( file );
                }
    
                public List<File> findMatchingFiles( File dirToWalk ) throws IOException {
                    this.walk( dirToWalk, this.files );
                    return this.files;
                }
            }.findMatchingFiles( dirToScan );
    
        }// list()
    
        private List<Segment> parseSegments( String pattern ) {
            String[] parts = StringUtils.split("/", pattern);
            List<Segment> segs = new ArrayList(parts.length);
            for( String part : parts ) {
                Segment seg = new Segment(part);
                segs.add( seg );
            }
            return segs;
        }
    
        class Segment {
            public final String pat;  // TODO: Tokenize
            private Segment( String pat ) {
                this.pat = pat;
            }
        }
    
    }// class