全局理解

Glob understanding

我需要在 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 表示 ** 表示递归,但如果我删除它,为什么它不起作用?

有人可以给我提示吗?

谢谢大家,周末愉快

*** 的区别在于 * 永远不会匹配目录分隔符(/\ 取决于您的 OS), 但 ** 会。给定这样的文件树:

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.

要使用从目录 /tmp/scanning/ 开始的 glob 递归查找 *.xml,请查看此示例。它与 Linux Ubuntu 一起工作,可以做你想做的事。它的工作方式类似于 Unix 查找实用程序。除了 Ubuntu,我没有在其他 OS 上测试它,但您应该只需要更改文件名分隔符。

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