Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one compare Path equivalence in Java?

Given two Path objects p1 and p2 (that do not necessarily point to a file that exists), how do I check the underlying paths are equivalent? That is, Path objects arising from

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

should (for instance) be regarded as equivalent / the same.

My current approaches would be to

  1. Use Files.isSameFile
  2. First apply .normalize() on each Path object and then use .equals on one of the new Paths.

Do these two approaches lead to the same result? I have tried to read the documentation, and my current guess is that the results should be the same.

Edit: Multiple people have suggested that the following article answers my question. I claim that this is incorrect, since it only explains why Files.isSameFile() is distinct from Path#equals(). The question (nor its answers) do not consider whether .normalize() is of relevance. Java NIO - How is Files.isSameFile different from Path.equals

like image 387
mstaal Avatar asked Jul 04 '26 09:07

mstaal


1 Answers

There is a difference between mentioned approaches in case of relative paths or reparse points:

  1. Files.isSameFile does a deep check, e.g. under Windows it opens both files and compares volume ids and file system indexes within that volume. So it can handle reparse points, relative paths, redundant path elements and even hardlinks (different file records pointing to same file contents). There are some pieces of decompiled byte code for Windows (I believe it will be similar for other systems):
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 only normalizes path string w/o accessing file system, so it can't match "/path/file.ext" and "./file.ext" when current directory is "/path" or "C:\dir\file.ext", "C:file.ext" and "\dir\file.ext" under Windows if current directory is "C:\dir", and it definitely doesn't follow links so may consider different routes to the same file as different files.

So depending on your needs there may be more than one sufficient approach:

  1. If you need the fastest way and know that there are no reparse points and both paths are absolute, it should be safe to use Path.normalize for both paths. You should use File.getAbsolutePath before normalizing if paths may be relative because normalization doesn't handle it.
  2. If you have to be absolutely sure that both paths refer to the same file, use Files.isSameFile.
  3. You can also use Path.toRealPath method for resolving any reparse points in path so applying it on both paths should give almost same result as Files.isSameFile but in a different way (maybe slower or faster, also it will not match hardlinks while Files.isSameFile will).
like image 183
mvitaly2003 Avatar answered Jul 07 '26 00:07

mvitaly2003



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!