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

I am looking for lib that will provide a method that will give me a list of files matching a given Ant pattern.

In *foo/**/*.txt I get

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

etc .. I know this is possible with DirWalker and

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

but I would prefer some supported lib. I expected Commons IO to get it, but no.

Update: I am pleased with reusing Ant code, but would prefer something smaller than whole Ants.

+7
source share
3 answers

So, I sacrificed several megabytes of application size for speed and used Ant DirectoryScanner at the end.

Also there Spring 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 so my point is, I started to code, not finish, just if someone would like to finish it. The idea was that it stores a stack of templates, traverses the tree and compares the contents with the actual depth of the stack, and the rest in the case ** .

But I turned to PathMatcher , and then to Ant 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 
+1
source

With Java 7, a recursive directory scan occurs. Java 8 can slightly improve it syntactically.

  Path start = FileSystems.getDefault().getPath(",,,"); walk(start, "**.java"); 

You need a glob matching class, best of all at the directory level, to skip directories.

 class Glob { public boolean matchesFile(Path path) { return ...; } public boolean matchesParentDir(Path path) { return ...; } } 

Then walking will be:

 public static void walk(Path start, String searchGlob) throws IOException { final Glob glob = new Glob(searchGlob); Files.walkFileTree(start, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (glob.matchesFile(file)) { ...; // Process file } return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return glob.matchesParentDir(dir) ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE; } }); } 

}

+1
source

Google Guava has TreeTraverser for files that allow you to enumerate files by depth and width in a directory. You can then filter the results based on the regular expression of the file name or whatever you need to do.

Here is an example (Guava required):

 import java.io.File; import java.util.List; import java.util.regex.Pattern; import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.io.Files; import com.google.common.collect.Iterables; import com.google.common.collect.TreeTraverser; public class FileTraversalExample { private static final String PATH = "/path/to/your/maven/repo"; private static final Pattern SEARCH_PATTERN = Pattern.compile(".*\\.jar"); public static void main(String[] args) { File directory = new File(PATH); TreeTraverser<File> traverser = Files.fileTreeTraverser(); Iterable<String> allFiles = Iterables.transform( traverser.breadthFirstTraversal(directory), new FileNameProducingPredicate()); Iterable<String> matches = Iterables.filter( allFiles, Predicates.contains(SEARCH_PATTERN)); System.out.println(matches); } private static class FileNameProducingPredicate implements Function<File, String> { public String apply(File input) { return input.getAbsolutePath(); } } } 

Guava will let you filter any Predicate using Iterables.filter, so you don't need to use a template if you don't want to.

0
source

All Articles