有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java库返回glob或Antlike模式“*foo/***/.txt”的列表<File>?

我正在寻找一个库,它将提供一个方法,该方法将为我提供一个文件列表,匹配给定的Ant-like模式

对于*foo/**/*.txt我会

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

等等,我知道用迪沃克和

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

,但我更喜欢一些。我以为Commons IO会有,但没有

更新:我很乐意重用Ant的代码,但我更喜欢比整个Ant更小的代码


共 (3) 个答案

  1. # 1 楼答案

    从Java7开始,有一个递归的目录扫描。Java8可以在语法上有所改进

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

    }

  2. # 2 楼答案

    因此,为了提高速度,我牺牲了几MB的应用程序大小,并最终使用了Ant'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
    

    这是我开始编写的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
    
  3. # 3 楼答案

    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过滤任何谓词。过滤器,所以如果不想使用模式,就不必使用模式