为什么 Path.relativize 在 Java 8 和 Java 11 上表现不同?

huangapple go评论83阅读模式
英文:

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.txtJava文档
  • [tag:java-11] (确切版本为11.0.4) 打印 ../file.txtJava文档

两个版本的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

问题

  1. [tag:java-8]的方式应该如何计算?它没有规范化路径吗?我不明白如何得出这个结果。

  2. 为什么这两个版本之间存在没有记录的差异?

英文:

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

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

  2. 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],它有额外的代码,包括 标准化

后者实现的关键行从 第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].

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());

huangapple
  • 本文由 发表于 2020年9月14日 00:02:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63872767.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定