Java PathMatcher在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的全局处理语法中未记录的行为。它似乎将反斜杠(在Windows文件系统中很常见)转换为正斜杠(反之亦然)。因此,它始终可以在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,它需要像{{1}这样输入})。
  • 第二组由两部分组成,其中第一部分再次在\\\\/之间进行检查,第二部分是在问题中输入的文本。

感谢@ user3775041提供了更整洁的正则表达式:

\

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

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

编辑:https://www.regexplanet.com/advanced/java/index.html

是测试Java正则表达式模式的好网站 ,

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

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

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

,

此代码适用于 windows 和 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);