首页 > 解决方案 > 如何比较 Java 中的路径等效性?

问题描述

给定两个 Path 对象 p1 和 p2(不一定指向存在的文件),我如何检查底层路径是否等效?也就是说,Path 对象产生于

/path/to/something
/path/to/../fdsfaf/something

应该(例如)被视为等效/相同。

我目前的方法是

  1. 使用 Files.isSameFile
  2. 首先在每个 Path 对象上应用 .normalize(),然后在其中一个新路径上使用 .equals。

这两种方法会导致相同的结果吗?我试图阅读文档,我目前的猜测是结果应该是一样的。

编辑:多人建议以下文章回答我的问题。我声称这是不正确的,因为它只解释了为什么 Files.isSameFile() 与 Path#equals() 不同。问题(及其答案)不考虑 .normalize() 是否相关。 Java NIO - Files.isSameFile 与 Path.equals 有何不同

标签: javafilepathcompare

解决方案


在相对路径或重解析点的情况下,上述方法之间存在差异:

  1. Files.isSameFile进行深度检查,例如在 Windows 下,它会打开两个文件并比较该卷中的卷 ID 和文件系统索引。因此它可以处理重解析点、相对路径、冗余路径元素甚至硬链接(指向相同文件内容的不同文件记录)。Windows有一些反编译的字节码(我相信其他系统也会类似):
public class WindowsFileSystemProvider extends AbstractFileSystemProvider {
    ...

    public boolean isSameFile(Path var1, Path var2) throws IOException {
        ...
        var11 = WindowsFileAttributes.isSameFile(var7, var10);
        ...
        return var11;
        ...
    }

    ...
}

class WindowsFileAttributes implements DosFileAttributes {
    ...

    static boolean isSameFile(WindowsFileAttributes var0, WindowsFileAttributes var1) {
        return var0.volSerialNumber == var1.volSerialNumber && var0.fileIndexHigh == var1.fileIndexHigh && var0.fileIndexLow == var1.fileIndexLow;
    }

    ...
}
  1. Path.normalize仅规范化不访问文件系统的路径字符串,因此当当前目录为“/path”或“C:\dir\file”时,它不能匹配“/path/file.ext”和“./file.ext”。如果当前目录是“C:\dir”,则 Windows 下的 ext”、“C:file.ext”和“\dir\file.ext”,并且它肯定不跟随链接,因此可能会考虑到同一个文件的不同路径不同的文件。

因此,根据您的需要,可能有不止一种足够的方法:

  1. 如果您需要最快的方法并且知道没有重解析点并且两条路径都是绝对的,那么两条路径都应该是安全的Path.normalize。如果路径可能是相对的,则应File.getAbsolutePath在规范化之前使用,因为规范化无法处理它。
  2. 如果您必须绝对确定两个路径都引用同一个文件,请使用Files.isSameFile.
  3. 您还可以使用Path.toRealPath方法来解决路径中的任何重解析点,因此在两条路径上应用它应该给出几乎相同的结果,Files.isSameFile但以不同的方式(可能更慢或更快,也不会匹配硬链接Files.isSameFile)。

推荐阅读