这是Java JDK中的一个错误吗?

21
当我用代码 File file = new File("e:/"); 来获取 java.lang.File 类时,它代表的是 e:\ 目录所对应的 File 类。
但如果我使用代码 File file = new File("e:"); 并且当前所在的路径是 E: 驱动器,那么它将代表当前目录所对应的 File 类。
假设我当前所在路径为 E:\dir\,并且该目录下有一个名为 Test.java 的文件。其内容如下:
import java.io.File;
public class Test {
    public static void main(String[] args) {
        File file = new File("e:"); 
        File[] files = file.listFiles(); 
        for(File f: files){ 
            System.out.println(f + " " + f.exists()); 
        }
    }
}

打开cmd工具,并导航到e:\dir目录,在其中执行以下命令:

E:\dir> javac Test.java
E:\dir> java Test

我收到了:

e:\Test.class false
e:\Test.java false

这是一个Java JDK的bug吗?


@JimGarrison提供的额外信息:

我运行了这段代码

public class Foo3
{
    public static void main(String[] args)  throws Exception
    {
        File f = new File("D:");
        System.out.println(f.getCanonicalPath());
        for (File x : f.listFiles())
            System.out.println(x + " " + x.getCanonicalPath() + " " + x.getAbsolutePath() + " " + x.exists() + " " + x.getAbsoluteFile().exists());
    }
}

我在D盘上运行的Eclipse中获得了以下输出:

D:\dev\src\pdxep
D:\.classpath D:\dev\src\pdxep\.classpath D:\dev\src\pdxep\.classpath false true
D:\.project D:\dev\src\pdxep\.project D:\dev\src\pdxep\.project false true
D:\.settings D:\dev\src\pdxep\.settings D:\dev\src\pdxep\.settings false true
D:\gallery D:\dev\src\pdxep\gallery D:\dev\src\pdxep\gallery false true
D:\pom.xml D:\dev\src\pdxep\pom.xml D:\dev\src\pdxep\pom.xml false true
D:\src D:\dev\src\pdxep\src D:\dev\src\pdxep\src false true
D:\target D:\dev\src\pdxep\target D:\dev\src\pdxep\target false true

这证实了有些有趣的事情正在发生。

Java Bug 8130462 似乎与此相关,因为它涉及到 Windows 中特定的相对路径和绝对路径问题。


1
非常好奇。我也能够重现这个问题。 - Jim Garrison
好的,实际上我有一个小差别。我是从我的f:驱动器运行的,而不是e:驱动器(但列出了e:驱动器)。将代码从“e:”更改为“f:”会导致错误的输出,与@JimGarrison观察到的问题和结果相符。因此,如果我仅使用驱动器字母并且在尝试列出文件的驱动器不同于当前驱动器,则对我来说可以正常工作。 - KevinO
1
我已经更新了问题并提供了更多信息。由于File中至少存在一个与绝对路径和相对路径有关的长期存在的错误,我怀疑这是另一个错误(或现有错误的结果,在我对问题的更新中链接了该错误)。 - Jim Garrison
这更可能是Windows API的特殊之处。 - user207421
这就是命令提示符中驱动器字母的工作方式,所以也许这不是一个错误,而是一个特性。 - Erich Kitzmueller
显示剩余4条评论
2个回答

1
关于使用代码File file = new File("e:");获取表示当前工作目录的File的第一部分不是错误,而是Windows的“驱动器相对路径”。也就是说,这是相对于指定驱动器中当前工作目录的路径。(是的,Windows每个驱动器都有一个不同的工作目录)
问题在于Java错误地在路径中添加了\,使得路径看起来像是绝对路径,并且可能因此错误地返回false,当调用file.exists()时。
然而,Java正确解析规范路径和绝对路径,并在x.getAbsoluteFile().exists()上正确返回true。正如您在示例代码中注意到的那样,Java还正确返回CWD的内容,即file.listFiles()
我在数据库中找到了一个旧的错误JDK-5066567,与此或非常相似。它创建于2004年,2013年被设置为“进行中”,当前的受让人是“不活跃的”,所以如果有修复,我们可能不会很快看到。

所以回答你的问题,我会说是的,这是一个错误。

然而,在java.nio.file.Path中处理起来似乎更好。因此,如果在您的用例中可以使用java.nio.file.*包,那么这可能是一个可接受的解决方法。


1

这不是一个bug。

  • E:/表示你同时指定了驱动器和目录。

  • E:表示你只指定了驱动器,目录则使用默认值。

注意:现在人们所谓的当前目录实际上是默认目录。也就是说,在未指定时应用的默认目录。如果根本没有指定驱动器,那么默认(当前默认)将适用。

这是大多数文件系统的工作方式。


关于默认目录的信息很有趣,我之前并不知道。你能提供一个链接让我了解更多吗?然而,无论如何file.exists()应该仍然返回true,这就是bug所在,所以对此我很抱歉但我认为你是错的。或者你有其他解释吗? - gustf
“当前工作目录”这个术语已经使用了几十年,这就是为什么例如pwd命令不会拼成pdd的原因。现在试图更改名称没有太大意义。 - user207421
@EJP,也许你可以解释一下为什么在古老的VMS命令语言(称为DCL)中,cd命令实际上是“set default”。顺便提一下,我需要提醒你Windows的首席架构师是Dave Cuttler,他也是VMS的架构师。 - Alain Pannetier
@gustf,file.exists()会添加默认目录(如果没有指定),或者使用指定的目录(如果有)。但我同意你所做的所有观察,并且这种行为至少是不一致的。 - Alain Pannetier
@gustf,在OpenVMS上的例子中,cd e:\ 会被调用为 set default e:\ 或者实际上是 set default $E:[000000]语法 - Alain Pannetier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接