javakotlinpathfilesystemsnio

How to compare FileSystem's of two Path's in kotlin/java?


I was wondering how I could check if fileSystems of two different paths are equal. It seems wrong to write something like

path1.fileSystem == path2.fileSystem

because there could be a case when file systems are the same by meaning (they are fully identical), but in fact are different instances and because of that path1.fileSystem == path2.fileSystem may return false when it must actually return true. Then how should I compare file systems of two different paths? Or is == actually okay and works correctly in this situation?

I actually tried asking ChatGPT, but it gave me a weird solution that doesn't seem to work

boolean sameFileSystem = FileSystems.getDefault().provider().getScheme().equals(path1.getFileSystem().provider().getScheme())
                && FileSystems.getDefault().provider().getScheme().equals(path2.getFileSystem().provider().getScheme());


Update: I need to check this in order to resolve one path against another (if the file systems are not the same I will just do something else, this part is irrelevant? i Just need to check if they are the same)


Solution

  • If you want to know whether you can safely invoke .resolve(Path) for two existing Path instances, you must check whether the two path belong to the same provider, rather than filesystem.

    Providers can be compared using the == operator; they are supposed to be singletons.

    For comparison, this is how Files.copy(…) checks whether the two paths belong to the same filesystem provider:

    public static Path copy(Path source, Path target, CopyOption... options)
        throws IOException
    {
        FileSystemProvider provider = provider(source);
        if (provider(target) == provider) {
            // same provider
            provider.copy(source, target, options);
        } else {
            // different providers
            CopyMoveHelper.copyToForeignTarget(source, target, options);
        }
        return target;
    }
    

    private static FileSystemProvider provider(Path path) {
        return path.getFileSystem().provider();
    }
    

    In most cases, a fallback using .resolve(String) works when you need to resolve with paths of different filesystem providers:

    static Path resolveWithForeignSupport(Path base, Path other) {
        FileSystem fs1 = base.getFileSystem(), fs2 = other.getFileSystem();
    
        if(fs1.provider() == fs2.provider()) {
            return base.resolve(other);
        }
    
        if(other.getNameCount() <= 1 || fs1.getSeparator().equals(fs2.getSeparator())){
            return base.resolve(other.toString());
        }
    
        Path resolved = base, othersRoot = other.getRoot();
        if(othersRoot != null) {
            resolved = resolved.resolve(othersRoot.toString());
        }
        for(Path component: other) {
            resolved = resolved.resolve(component.toString());
        }
        return resolved;
    }