2013-06-04 35 views
7

我正在尋找一個lib,它會提供一個方法,它會給我一個與給定的類Ant模式相匹配的文件列表。Java庫爲glob或類Ant模式「* foo/**/*。txt」返回List <File>?

對於*foo/**/*.txt我會得到

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

等我知道這是可以實現的與DirWalker和

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

,但我寧願保持一些LIB。我期望Commons IO擁有它,但不是。

更新:我很高興重複使用Ant的代碼,但寧願小於整個Ant的東西。

+0

'的File.List(的FilenameFilter)'也沒有什麼幫助? – sanbhat

+0

這不是遞歸的。 –

回答

1

所以我爲了速度犧牲了幾MB的應用程序大小,最後使用Ant's DirectoryScanner

此外,還有春天的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 

這裏是我的impl我開始編碼,沒有完成,只是如果有人想完成它。這個想法是它會保留一堆模式,遍歷目錄樹,並在**的情況下將內容與實際堆棧深度及其餘部分進行比較。

但我訴諸PathMatcher,然後到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 
0

Google Guava有文件TreeTraverser,讓你做的文件深度優先和廣度優先枚舉目錄中。然後你可以根據文件名的正則表達式來過濾結果,或者你需要做的任何事情。

下面是一個例子(需要番石榴):

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

} 

番石榴可以讓你通過任何謂詞篩選,使用Iterables.filter,所以你不必使用一個模式,如果你不想。

1

從Java 7開始,有一個遞歸目錄掃描。 Java 8可以在語法上稍微改進它。

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

需要一個glob匹配類,最好在目錄級別,以跳過目錄。

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

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

然後步行將是:

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

請您詳細說明Glob嗎?我不太清楚如何實現缺少的部分。 – garci560

+0

我的答案並不是最優的,因爲它不使用glob模式中的常量部分,比如'/ src/main /'。 Glob可以在搜索'* foo'的currect目錄中以每個標題子目錄開始,'* foo/**/*。txt'開始執行。 –