【问题标题】:Java NIO Search file in a directoryJava NIO 搜索目录中的文件
【发布时间】:2018-12-11 08:46:31
【问题描述】:

我想使用 Java NIO 和 glob 在特定目录中搜​​索文件(不知道全名)。

public static void match(String glob, String location) throws IOException {

        final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(
                glob);

        Files.walkFileTree(Paths.get(location), new SimpleFileVisitor<Path>() {

            @Override
            public FileVisitResult visitFile(Path path,
                    BasicFileAttributes attrs) throws IOException {
                if (pathMatcher.matches(path)) {
                    System.out.println(path);
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

阅读一些教程我做到了这一点。如果我找到(第一个)具有给定 glob 字符串的文件,我只想返回字符串。

if (pathMatcher.matches(path)) {
    return path.toString();
}

【问题讨论】:

    标签: java file nio glob


    【解决方案1】:

    有两点需要改变:

    要“查找(第一个)具有给定 glob 字符串的文件”,如果遇到文件,则需要完成遍历树,因此如果给出了匹配项。并且您需要将匹配的路径存储为结果。 Files.walkFileTree 本身的结果是“起始文件”(JavaDoc)。那是一个Path 指向location

    public static String match(String glob, String location) throws IOException {
        StringBuilder result = new StringBuilder();
        PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
        Files.walkFileTree(Paths.get(location), new SimpleFileVisitor<Path>() {
    
            @Override
            public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
                if (pathMatcher.matches(path)) {
                    result.append(path.toString());
                    return FileVisitResult.TERMINATE;
                }
                return FileVisitResult.CONTINUE;
            }
        });
    
        return result.toString();
    }
    

    如果没有匹配,则生成的 String 为空。

    编辑:
    使用Files.walk,我们可以用更少的代码实现搜索,但仍然使用基于 glob 表达式的匹配器:

    public static Optional<Path> match(String glob, String location) throws IOException {
        PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
        return Files.walk(Paths.get(location)).filter(pathMatcher::matches).findFirst();
    }
    

    Optional 作为结果表明可能没有匹配。

    【讨论】:

    • 使用可以为空的String 而不是StringBuilder。这减少了开销,而且仍然准确
    • 这应该如何工作? String 变量将不再有效。
    • 你是对的。如果您使用 Java 11+,则可以使用 AtomicReference 或使用 var wrapper = new Object() { Path reference; }
    • 你认为这会更具可读性吗?这是因为如果没有找到结果,您更喜欢返回null 而不是空的String
    • try(Stream&lt;Path&gt; stream = Files.find​(Paths.get(location), Integer.MAX_VALUE, (path,attr) -&gt; pathMatcher.matches​(path))) { return stream.findFirst().orElse(null); }
    【解决方案2】:

    基于您自己的代码。一旦找到匹配项就停止遍历

    public class Main {
    
        private static Path found = "nothing"; // First file found
    
        public static void main(String[] args) throws IOException {
            String glob = "glob:**.{java}"; //pattern to look for
            String location = "D:\\"; //where to search
            match(location, glob);
            System.out.println("Found: " + found);
        }
    
        public static void match(String location, String glob) throws IOException {
    
            final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
    
            Files.walkFileTree(Paths.get(location), new SimpleFileVisitor<Path>() {
    
                @Override
                public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
                    if (pathMatcher.matches(path)) {
                        found = path; // Match found, stop traversal
                        return FileVisitResult.TERMINATE;
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }
    

    或者你可以填充集合保存所有匹配模式的文件

    【讨论】:

    • 我不确定您希望 {prop*} 做什么,但我会避免将 {alt1,alt2,...} 语法与通配符混合。我刚刚在bash 下对其进行了测试,内部通配符没有被扩展,而是被理解为文字*。我没有用 Java 测试过,所以它可能只是工作,但你至少肯定会让熟悉 linux 的人感到困惑
    • @Aaron 用它在 Windows 中查找属性。不确定 bash 但你是对的,最好编辑以避免潜在的麻烦
    • 另外,OP 想要 return 一个字符串。能不能把found放到match方法中,在方法结束时返回,让void-returning方法变成Path-returning方法?
    【解决方案3】:

    我不知道这个示例是否可以进一步帮助您,但您似乎需要自己的自定义文件访问器。这是一个替代解决方案:

    package com.jesperancinha.files;
    
    import java.nio.file.FileSystems;
    import java.nio.file.FileVisitResult;
    import java.nio.file.Path;
    import java.nio.file.PathMatcher;
    import java.nio.file.SimpleFileVisitor;
    import java.nio.file.attribute.BasicFileAttributes;
    
    public class GlobFileVisitor extends SimpleFileVisitor<Path> {
        private final PathMatcher pathMatcher;
    
        private Path path;
    
        public GlobFileVisitor(String glob) {
            this.pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
        }
    
        @Override
        public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
            if (pathMatcher.matches(path)) {
                this.path = path;
                return FileVisitResult.TERMINATE;
            }
            return FileVisitResult.CONTINUE;
        }
    
        public Path getFoundPath() {
            return path;
        }
    }
    

    这是您运行示例的另一种可能性:

    package com.jesperancinha.files;
    
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class FileFinder {
        public static void main(String[] args) throws IOException {
            String glob = "glob:**.{java}";
            String location = "/Users/joao/dev/src/jesperancinha";
            Path found = match(location, glob);
            System.out.println("Found: " + found);
        }
    
        public static Path match(String location, String glob) throws IOException {
            GlobFileVisitor globFileVisitor = new GlobFileVisitor(glob);
            Files.walkFileTree(Paths.get(location), globFileVisitor);
            return globFileVisitor.getFoundPath();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      相关资源
      最近更新 更多