Java PathMatcher 在 Windows 上无法正常工作

Java PathMatcher not working properly on Windows

我尝试为我的 SimpleFileVisitor 实施 JUnit 测试,但使用的 PathMatcher 在 Windows 上无法正常工作。问题似乎是具有正则表达式模式的 PathMatcher 在 Linux 和 Windows:

上表现不同
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;

public class TestApp{

     public static void main(String []args){
        final PathMatcher glob = FileSystems.getDefault().getPathMatcher("glob:{/,/test}");
        final PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:/|/test");

        System.err.println(glob.matches(Paths.get("/")));       // --> Linux=true  Windows=true
        System.err.println(glob.matches(Paths.get("/test")));   // --> Linux=true  Windows=true
        System.err.println(glob.matches(Paths.get("/test2")));  // --> Linux=false Windows=false

        System.err.println(regex.matches(Paths.get("/")));      // --> Linux=true  Windows=false
        System.err.println(regex.matches(Paths.get("/test")));  // --> Linux=true  Windows=false
        System.err.println(regex.matches(Paths.get("/test2"))); // --> Linux=false Windows=false
     }  
}

但是我的正则表达式中有一个更长的列表,用于多个文件,这些文件不容易迁移到 glob 语法。否则,如果我将每个模式都写为未分组模式,我会嵌套不允许的组或更长的列表。

以跨平台方式执行此操作的最佳方法是什么?

首先我想说这是 PathMatcher 的 glob 处理语法中未记录的行为。它似乎将反斜杠(在 Windows 文件系统上很常见)转换为正斜杠(或 vice-versa)。从而使其始终在 Linux 和 Windows.

之间工作

下一行演示了不同的输出:

System.out.println(Paths.get("/test")); // Will output '\test' on Windows, '/test' on Linux

为了解决最初的问题,我们需要使用一些 RegexFu。

FileSystems.getDefault().getPathMatcher("regex:/|/test");

需要成为

FileSystems.getDefault().getPathMatcher("regex:(/|\\)|((/|\\)test)");
  • 第一组将检查 /\ 之间(您需要 \ 来转义 \,但是因为 Java 它需要输入 \\).
  • 第二组由两部分组成,第一部分再次检查 /\,第二部分是问题中输入的文本。

感谢@user3775041 提供了更清晰的正则表达式:

FileSystems.getDefault().getPathMatcher("regex:[/\\]|[/\\]test");

这已经在 Windows 10 和 Ubuntu 20.04 上进行了测试,两者都具有以下输出:

true
true
false
true
true
false

编辑:Java 中测试正则表达式模式的好网站是 https://www.regexplanet.com/advanced/java/index.html

如果您想要一个在 Linux 上代码为 运行 时正则表达式中不包含 Windows 文件分隔符的版本,您还可以使用:

String sep = Pattern.quote(File.separator);
PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:"+sep+"|"+sep+"test");

这会在 Linux/Windows 上打印相同的输出。

此代码适用于 window 和 linux:

    String pattern = "regex:\./src/main/java/.*\.java|\./src/main/java/.*\.txt";
    String newPattern;
    
    if(File.separator.equals("\")) { //window fix
        newPattern = pattern.replace("/", "\\"); 
    }else { //linux
        newPattern = pattern;
    }
    
    PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(newPattern);