全局理解

3

我需要用Java开发一个文件扫描器,具有以下选项/参数:

  1. 一个目录
  2. 一个或多个模式,如*.xml、*.txt、*test.csv
  3. 递归扫描开关

我认为最好的方法是类似于以下方式:

public class FileScanningTest {

    public static void main(String[] args) throws IOException {

        String directory = "C:\\tmp\\scanning\\";
        String glob      = "**/*.xml";
        Boolean rekursiv = false;

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

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

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

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });

    }

}

我不明白为什么我必须在实际模式前面放置“**/”。同时这确实使扫描递归。如果我删除 **/,应用程序将不再找到任何内容。 https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob 告诉我们 ** 表示递归,但是如果我去掉它为什么它就不能工作呢?
有人能给我一个提示吗?
谢谢大家,祝你们周末愉快。
2个回答

4

请看以下示例,通过使用glob从目录/tmp/scanning/开始递归查找*.xml。它在Linux Ubuntu上运行,并且可以实现你想要的功能。它的工作方式类似于Unix中的find实用程序。我没有在Ubuntu以外的其他操作系统上进行测试,但你只需要更改文件名分隔符。

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;

import static java.nio.file.FileVisitResult.*;
import static java.nio.file.FileVisitOption.*;

import java.util.*;


public class FileScanningTest {

    public static class Finder
            extends SimpleFileVisitor<Path> {

        private final PathMatcher matcher;
        private int numMatches = 0;

        Finder(String pattern) {
            matcher = FileSystems.getDefault()
                    .getPathMatcher("glob:" + pattern);
        }

        // Compares the glob pattern against
        // the file or directory name.
        void find(Path file) {
            Path name = file.getFileName();
            if (name != null && matcher.matches(name)) {
                numMatches++;
                System.out.println(file);
            }
        }

        // Prints the total number of
        // matches to standard out.
        void done() {
            System.out.println("Matched: "
                    + numMatches);
        }

        // Invoke the pattern matching
        // method on each file.
        @Override
        public FileVisitResult visitFile(Path file,
                                         BasicFileAttributes attrs) {
            find(file);
            return CONTINUE;
        }

        // Invoke the pattern matching
        // method on each directory.
        @Override
        public FileVisitResult preVisitDirectory(Path dir,
                                                 BasicFileAttributes attrs) {
            find(dir);
            return CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file,
                                               IOException exc) {
            System.err.println(exc);
            return CONTINUE;
        }
    }


    public static void main(String[] args)
            throws IOException {
        boolean recursive = false;
        Path startingDir = Paths.get("/tmp/scanning");
        String pattern = "*.{html,xml}";

        Finder finder = new Finder(pattern);
        if (!recursive) {
            Path dir = startingDir;
            List<File> files = new ArrayList<>();
            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{xml,html}")) {
                for (Path entry : stream) {
                    files.add(entry.toFile());
                }

                for (File xmlfile : files) {
                    System.out.println(xmlfile);
                }
            } catch (IOException x) {
                throw new RuntimeException(String.format("error reading folder %s: %s",
                        dir,
                        x.getMessage()),
                        x);
            }
        } else {    
            Files.walkFileTree(startingDir, finder);
            finder.done();
        }

    }
}

测试

 ~> java FileScanningTest
/tmp/scanning/dir2/test2.xml
/tmp/scanning/blah.xml
Matched: 2

如果您想匹配*.xmltest3.html,则可以使用此模式:String pattern = "{*.xml,test3.html}";


谢谢。这也适用于Windows平台。但是我如何禁用递归扫描?我们有一个选项可以禁用递归扫描。还有一种同时使用几个不同模式的方法吗? - Hauke
1
如果您能更新您的代码,那就太好了。这只是一个测试类,使用布尔标志“recursive”而不是分析应用程序参数也可以。感谢您的帮助。 - Hauke
@Hauke 现在请再次尝试代码。它有两个分支,一个用于递归,一个用于非递归。还有一个布尔值用于选择是否递归。现在可以找到HTML和XML。 - Niklas Rosencrantz
1
工作得很好。我该如何做一个类似“*.xml”和“test*.html”的模式? - Hauke
由于我不知道花括号的用法,所以我的逗号分隔的通配符无法正常工作,最后一行请给个加1。 - Ismail Yavuz
显示剩余4条评论

1
< p > *** 的区别在于,* 永远不会匹配目录分隔符(/\ 取决于您的操作系统),但是 ** 会。 假设有这样一棵文件树:

a/
  b.xml
c/
  a.xml
da.xml

模式*a.xml只会匹配da.xml(不会匹配c/a.xml,因为它包含一个/),而模式**a.xml将匹配da.xmlc/a.xml,模式a**.xml只会匹配a/b.xml

谢谢提供的信息。这意味着如果我已经在目录中,我只能使用*a.xml这种模式,而不需要提供完整路径对吗? - Hauke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接