Search code examples
javafilesystemsjava-7nio

Real-life usage of Path.relativize() if source path contains anything else than real folders


While preparing a java 7 certification exam, I had to start looking closely at the Path.relativize() method. While superficially its purpose seems straight forward, express a path relatively to another, I have found that its implementation defies all understanding I had of filesystems, namely on Windows or Linux/Unix.

Consider the following:

// Case 1
System.out.println(Paths.get("c:\\folder1\\folder2").relativize(Paths.get("c:\\file.txt")));

// Case 2
System.out.println(Paths.get("c:\\folder1\\folder2\\other-file.txt").relativize(Paths.get("c:\\file.txt")));

// Case 3
System.out.println(Paths.get("c:\\folder1\\..\\.\\folder1\\..\\.\\folder1\\..\\.\\folder1\\..").relativize(Paths.get("c:\\file.txt")));

The output I got is:

..\..\file.txt
..\..\..\file.txt
..\..\..\..\..\..\..\..\..\..\..\file.txt

Case 1 illustrates the straight forward usage one could expect of that function, i.e. find the path of a file relatively to a folder, given the absolute paths of both file and folder. Fine, that gives me something I can type in a cmd window in Windows and will find my file correctly.

Case 2, as discussed in other StackOverflow questions, highlights the fact that the method has no way of distinguishing a file name from a folder name (a folder can contain a . in its name, and a file can have none). OK, to me this should mean the method should come with the caveat: "use at your own risk, if providing a path where the leaf is a file, the relativized result won't work in a file system". Or does it, if yes, which file system?

Case 3 to me is nonsense. The method does not even take into account the meaning of "." and ".." in the source path, but happily uses ".." in the result as a way to go up a level in the source folder. This may make sense in a theoretical filesystem I'm yet to encounter, but in Windows, Linux or Unix, the result is unusable. "..\..\..\..\..\..\..\..\..\..\..\file.txt" will of course not point to file.txt relatively to a path that despite being expressed as "c:\folder1\..\.\folder1\..\.\folder1\..\.\folder1\.." really points to "c:\".

Thanks for hanging in so far. The question: what possible use could one make of the Path.relativize() method considering its results only make real-life sense in a fraction of cases?


Solution

  • Your expression

    Paths.get("c:\\folder1\\..\\.\\folder1\\..\\.\\folder1\\..\\.\\folder1\\..")
    

    is really just c:\ when normalized.

    If you then relativize c:\file.txt against that path, you get a relative path that will lead you there. From c:\, that relative path is file.txt.

    The result

    ..\..\..\..\..\..\..\..\..\..\..\file.txt
    

    is exactly equivalent to file.txt. When normalized, leading .. will be discarded. I agree it isn't pretty, but that's just an implementation detail.