英文:
Why does Path.relativize behave differently on Java 8 and Java 11?
问题
为什么relativize
方法在[tag:java-8]和[tag:java-11]上表现不同?
Path path1 = Paths.get("/a/./b/../image.png");
Path path2 = Paths.get("/a/file.txt");
Path path = path1.relativize(path2);
System.out.println(path);
- [tag:java-8] (确切版本为1.8.0_66) 打印
../../../../file.txt
。Java文档。 - [tag:java-11] (确切版本为11.0.4) 打印
../file.txt
。Java文档。
两个版本的Java文档描述是相同的。我觉得[tag:java-11]的方式对我来说看起来是正确的行为:
path1
:/a/./b/../image.png
规范化为/a/b/../image.png
,然后规范化为/a/image.png
path2
:/a/file.txt
- 从
/a/image.png
到/a/file.txt
的导航方式是../file.txt
问题
-
[tag:java-8]的方式应该如何计算?它没有规范化路径吗?我不明白如何得出这个结果。
-
为什么这两个版本之间存在没有记录的差异?
英文:
Why does the method relativize
behave differently on [tag:java-8] and [tag:java-11]?
Path path1 = Paths.get("/a/./b/../image.png");
Path path2 = Paths.get("/a/file.txt");
Path path = path1.relativize(path2);
System.out.println(path);
- [tag:java-8] (1.8.0_66 to be exact) prints
../../../../file.txt
. JavaDoc. - [tag:java-11] (11.0.4 to be exact) prints
../file.txt
. JavaDoc.
The JavaDoc description of both versions is equal. I feel the [tag:java-11] way looks like a correct behavior to me:
path1
:/a/./b/../image.png
normalizes to/a/b/../image.png
which normalizes to/a/image.png
path2
:/a/file.txt
- the way to navigate from
/a/image.png
and/a/file.txt
is../file.txt
Questions
-
How is the [tag:java-8] way supposed to be calculated? Doesn't it normalize the path? I don't understand how to get the result from head.
-
Why is there a difference between these two versions that is not documented at all?
答案1
得分: 6
也许这个错误会解答你的问题:
https://bugs.openjdk.java.net/browse/JDK-8066943
这影响了包含"."或".."的路径相对化,并在Java 9中修复了。
所以这就是为什么你在8和11之间看到了差异。
英文:
Maybe this bug will answer your question:
https://bugs.openjdk.java.net/browse/JDK-8066943
This affected relativizing paths containing . or .. and was fixed for Java 9.
So that's why you see a difference between 8 and 11.
答案2
得分: 2
基于Windows的源代码回答如下:
从源代码的观察(让我们看一下 sun.nio.fs.WindowsPath
,这是 Path
实现之一)中可以发现,在 [tag:java-11] 中相对于 [tag:java-8],它有额外的代码,包括 标准化。
- [tag:java-8]
sun.nio.fs.WindowsPath
GitHub 上的源代码 - [tag:java-11]
sun.nio.fs.WindowsPath
GitHub 上的源代码
后者实现的关键行从 第411行 开始,因此基本上,后者的实现在计算相对路径之前会标准化路径:
WindowsPath base = this;
if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
base = base.normalize();
child = child.normalize();
}
进一步深入挖掘,在 jdk8-b120
(源代码)和 jdk-9+95
(源代码)之间发生了实现变化。自从模块化系统被引入以来,两个类的实现和位置都有所不同:
- Java 8 及更早版本:
/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
- Java 9 及更高版本:
/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsPath.java
> [tag:java-8] 的方式是如何计算的?它不会对路径进行标准化吗?我不明白如何从头脑中得出结果。
最直接的方法是在进行相对化之前先标准化两个路径。但我不知道是否完全涵盖了所有的 java.nio.file.Path
实现,并且是否安全这样做。
Path path = path1.normalize().relativize(path2.normalize());
英文:
Windows based source-code answer here.
From the observation of the source codes (let's take a look at sun.nio.fs.WindowsPath
, one of the implementations of Path
) in [tag:java-11] is has additional code including normalization compared to [tag:java-8].
- [tag:java-8]
sun.nio.fs.WindowsPath
source code at GitHub - [tag:java-11]
sun.nio.fs.WindowsPath
source code at GitHub
The key line of the latter implementation starts at the line 411, so basically, the latter implementation normalizes the paths before taking into calculation of the relative path:
WindowsPath base = this;
if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
base = base.normalize();
child = child.normalize();
}
Digging further, the implementation changes between jdk8-b120
(source) and jdk-9+95
(source). Since the modular system was introduced, both the classes implementation and location differ:
- Java 8 and below:
/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
- Java 9 and above:
/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsPath.java
> How is the [tag:java-8] way supposed to be calculated? Doesn't it normalize the path? I don't understand how to get the result from head.
The most straightforward way to go is to normalize both paths first before relativizing them. But I have no idea whether it completely covers all the java.nio.file.Path
implementations and is safe to do so.
Path path = path1.normalize().relativize(path2.normalize());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论