2013-06-04 15 views
7

Poszukuję lib, który dostarczyłby metodę, która dałaby mi listę plików pasujących do podanego wzoru Ant-like.Biblioteka Java, aby zwrócić listę <File> dla globu lub wzorca Ant-like "* foo/**/*. Txt"?

Dla *foo/**/*.txt bym dostać

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

itd. Wiem, że jest osiągalny z DirWalker i

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

, ale wolałbym jakiś utrzymany lib. Spodziewałem się, że Commons IO to będzie mieć, ale nie.

Aktualizacja: Jestem zadowolony z ponownego użycia kodu Ant, ale wolałbym coś mniejszego niż cały Ant.

+0

'File.list (FileNameFilter) nie' również pomocne? – sanbhat

+0

To nie jest rekurencyjne. –

Odpowiedz

1

Tak więc poświęciłem kilka MB rozmiaru aplikacji ze względu na szybkość i ostatecznie użyłem Ant's DirectoryScanner.

Istnieje również wiosna 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 

A oto moje Impl zacząłem kodu, a nie gotowym, tylko jeśli ktoś chciałby ją zakończyć. Pomysł polegał na tym, że zachowywałby stos wzorców, przechodził przez drzewo katalogów i porównywał zawartość z rzeczywistą głębokością stosu, a resztą w przypadku **.

Ale uciekłem się do PathMatcher, a następnie do implanta Anta.

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 
0

Google Guava ma TreeTraverser plików, który pozwala zrobić najpierw w głąb i wszerz wyliczanie plików w katalogu. Następnie możesz filtrować wyniki w oparciu o wyraże- nie nazwy pliku lub cokolwiek innego, co musisz zrobić.

Oto przykład (wymaga Guava):

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 pozwoli Ci filtrować według dowolnego orzecznikiem za pomocą Iterables.filter, dzięki czemu nie trzeba używać Wzorzec, jeśli nie chcą .

1

Od wersji 7 Java jest skaner katalogu rekursywnego. Java 8 może nieco poprawić ją składniowo.

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

Potrzebna jest klasa dopasowania globalnego, najlepiej na poziomie katalogu, aby pomijać katalogi.

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

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

Następnie chodzenie byłoby:

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; 
     } 
    }); 
} 

}

+0

Mógłbyś rozwinąć na Globie? Nie jestem do końca pewien, jak zaimplementować brakujące części. – garci560

+0

Moja odpowiedź nie jest optymalna, ponieważ nie wykorzystuje stałych części wzoru globalnego, takich jak '/ src/main/'. Glob może zostać zaimplementowany zaczynając od każdego podkatalogu nagłówka, '* foo/**/*. Txt' jako pierwszy w katalogu katalogów szukających' * foo'. –