【问题标题】:java.io.File.<init>(File,String) JDK version dependent [duplicate]java.io.File.<init>(File,String) JDK 版本相关 [重复]
【发布时间】:2018-09-03 13:54:02
【问题描述】:

看起来 java.io.File.(File, String) 依赖于 JDK 版本。 代码示例在 Windows 10 上运行。

代码示例:

public static void main(String... args) {
    String path = "C:\\Workspace\\project";
    File file = null;
    for (String part : path.split("\\\\")) {
        file = new File(file, part);
    }
    System.out.println(file);
    // prints "C:Workspace\project" for JDK 9+
    // prints "C:\Workspace\project" for JDK 8
}

能否请您说明该案例是否有任何已知问题或解决方案

【问题讨论】:

  • 新行为似乎是正确的。 C: 表示驱动器 C 上的当前目录,当您附加 Workspace 时,它应该成为相对的 C:Workspace。如果你以 `C:\` 开头,那么你应该得到另一个结果。
  • 我想知道 JEP 326: Raw String Literals (#File Paths Example) 是否真的有用。

标签: java file java-8 java-io java-9


【解决方案1】:

在 Java 9 中,WinNTFileSystem 类(Windows 的文件系统实现)发生了变化。
它可能解决了类认为绝对路径是什么的方式的问题。我没有找到确切指定这个的错误,但有些接近。

File.isAbsolute() 状态:

在 Microsoft Windows 系统上,如果路径名的前缀是 驱动器说明符后跟“\”,或者如果它的前缀是“\\”。

所以根据规范,对于以下内容:

File x = new File("C:", "Workspace"); 
System.out.println(x.isAbsolute()); // not absolute according to the spec

File xx = new File("C:\\", "Workspace");
System.out.println(xx.isAbsolute());

File xxx = new File("\\\\Workspace");
System.out.println(xxx.isAbsolute());

我们期望:

假的 真的 真的

但我们得到:

真 真的 真的

从 Java 9 开始,它会产生预期的结果。

问题是在 Java 9 之前没有\ 的路径都被视为绝对路径:

File x = new File("C:", "Workspace");
System.out.println(x.isAbsolute()); // true

虽然情况不应该如此。

具体来说,主要变化涉及WinNTFileSystem 类的resolve(String parent, String child) 方法。
之前,resolve() 通过在父子路径之间添加斜杠来解析抽象路径,以用于任何不以斜杠开头的子路径。
从 Java 9 开始,如果父项是驱动器,resolve() 将不再在父项和子项之间添加斜杠。

这里是change

boolean isDirectoryRelative =
    pn == 2 && isLetter(parent.charAt(0)) && parent.charAt(1) == ':';

if (child.charAt(childStart) == slash || isDirectoryRelative) {
    theChars = new char[strlen];             ^-------- this one was added from Java 9
    parent.getChars(0, parentEnd, theChars, 0);
    child.getChars(childStart, cn, theChars, parentEnd);
} else {
    theChars = new char[strlen + 1];
    parent.getChars(0, parentEnd, theChars, 0);
    theChars[parentEnd] = slash;
    child.getChars(childStart, cn, theChars, parentEnd + 1);
}

后果

关于你的问题:

请问您是否有任何已知问题或解决方案 案例

两个 JDK 版本之间的差异很重要。 它涉及抽象路径名的规范化路径名 (File.getPath()) 的值和绝对路径 File.getAbsolutePath() 的值,因为现在 new File("C:", "Workspace") 生成相对路径。

如果您的应用程序依赖 File.getPath() 对其进行一些解析,则它可能会有不同的行为并产生一些问题。
要在 JDK 版本之间拥有可移植的代码,解析路径上的任何解析都应视为可选的 \,紧跟在 Windows 驱动器之后。
这样C:\C: 将以相同的方式处理。

如果您的应用程序依赖于File.getAbsolutePath(),Java 9 也可能会带来一些惊喜,因为现在相对路径将针对文件系统进行解析(之前作为绝对路径,它只是返回自身)。
所以相反,你应该使用File.getPath() 来不解析文件系统的路径。

【讨论】:

    【解决方案2】:

    除了@david 的回答,

    这是一个bug#8153250,这是地址和固定版本可用JDK 9 b153

    【讨论】:

    • 这应该是您分享的 Bug 中链接的 SO 问题的副本吗?似乎正确的实现是该修复在 JDK-10 或更高版本中所暗示的。
    • @nullpointer 即使我认为,它也是同一个问题的重复。 JDK10中修复了与相同错误(实际上在相同错误中提到)相关的类似问题。
    【解决方案3】:

    正如@davidxxx 指出的那样,初始文件实例上的getAbsoluteFilegetAbsolutePath 对于Java8 和Java9 是相同的。但是,如果您决定使用这个初始文件来创建一个新文件,您可能会对这些差异感到惊讶——至少我是。

    public static void main(String[] args) throws Exception {
    
        File file = new File((File)null, "C:");
        System.out.println(file);
        System.out.println(file.getAbsoluteFile());
    
        System.out.println("----");
    
        file = new File(file, "Windows");
        System.out.println(file);
        System.out.println(file.getAbsoluteFile());
    }
    

    如果您使用 Java 8 和 9 执行上述程序,file 在第二次分配后将指向完全不同的文件夹。由于 Java8 和 9 的初始文件相同,我实际上认为这是 Java 8 中的一个错误(可能更早)。

    输出 Java 8:

    C:
    C:\ws\PLAYGROUND\test
    ----
    C:\Windows
    C:\Windows

    输出 Java 9:

    C:
    C:\ws\PLAYGROUND\test
    ----
    C:Windows
    C:\ws\PLAYGROUND\test\Windows

    【讨论】:

      猜你喜欢
      • 2012-02-21
      • 2021-05-04
      • 2011-01-02
      • 2021-04-20
      • 2019-10-18
      • 2020-04-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      相关资源
      最近更新 更多