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?
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.