我正在寻找一个库,它将提供一个方法,它将给我一个匹配给定蚂蚁模式的文件列表。
对于*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更小的代码。
所以我为了速度牺牲了几个MB的应用程序大小,最后使用了Ant的DirectoryScanner
。
还有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
这是我的impl我开始编码,没有完成,只是如果有人愿意完成它。这个想法是,它将保持一个模式堆栈,遍历dir树,并将内容与实际堆栈深度和**
的其余部分进行比较。
但我求助于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
从Java 7开始,有一个递归目录扫描。Java 8可以在语法上稍微改进一下。
Path start = FileSystems.getDefault().getPath(",,,");
walk(start, "**.java");
需要一个全局匹配类,最好是在目录级别,以便跳过目录。
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;
}
});
}
}
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();
}
}
}
Guava将允许您使用Iterables根据任何谓词进行过滤。