Java:设置“user.dir”时File.exists()不一致

时间:2010-02-16 18:39:54

标签: java filesystems

JRE 6,在Windows XP上。

使用不同的构造函数实例化两个File对象会导致File.exists()方法中的结果不一致。

免责声明: 以下代码是摘要,而不是实际代码。我根本不相信这是一个File.separator问题。我首先要求得到早期反应,以防我错过了一个很好理解的问题。现在看来重置user.dir系统属性是造成这个问题的原因之一。下面的代码现在可以重现并且可以按原样使用。您可以复制/粘贴Java类并尝试它,它应该与我列出的结果一致。

设定:

创建文件夹架构C:\toto\tmp\sub

从任何不包含tmp/sub子文件夹架构的文件夹中启动以下类。

代码:

public class TestFileExists {

    public static void main(String[] args) {

        System.setProperty("user.dir", "C:\\toto\\");

        File root = new File("tmp");

        File sub_a = new File(root, "sub");

        File sub_b = new File(root.getAbsolutePath()+"/sub");

        System.out.println("sub_a path ? "+sub_a.getAbsolutePath());
        System.out.println("sub_a exists ? "+sub_a.exists());
        System.out.println("sub_b path ? "+sub_b.getAbsolutePath());
        System.out.println("sub_b exists ? "+sub_b.exists());
        System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath())));
        System.out.println("Obj equals ? "+ (sub_a.equals(sub_b)));

    }

}

结果:

sub_a path ? C:\toto\tmp\sub
sub_a exists ? false
sub_b path ? C:\toto\tmp\sub
sub_b exists ? true
Path equals ? true
Obj equals ? false

我不理解行sub_a exists ? false并且结果在机器之间不一致,也没有与根初始路径一致 ant结果现在与从机器到机。

现在,如果通过从命令行调用java来重新执行该类,则从包含tmp/sub子文件夹体系结构的文件夹(如果从D:\调用它)开始,{{1 }},你会得到预期的:

D:\tmp\sub

但是sub_a path ? C:\toto\tmp\sub sub_a exists ? true sub_b path ? C:\toto\tmp\sub sub_b exists ? true Path equals ? true Obj equals ? false 的存在显然是误报,因为它会检查另一个文件夹是否存在而不是sub_a所描述的文件夹。

所以我强烈怀疑getAbsolutePath()取决于实际的Java执行路径,并且该文件存在与绝对路径不一致,File.exists()使用的路径不是“user.dir”系统用于检查文件系统的属性。

知道这个问题可能来自哪里?

7 个答案:

答案 0 :(得分:10)

不支持设置user.dir。它应该被视为只读属性。

例如,Sun Bug Parade中Bug 4117557的评估包含以下文字:

  在jvm启动期间初始化的

“user.dir”应该用作   informative / readonly系统属性,尝试通过命令行自定义它   -Duser.dir = xyz将以实现dependend / unspecified行为结束。

虽然本文是关于在命令行上设置它,但通过setProperty()进行设置很可能同样未定义。

当您可以手动重现问题而不设置user.dir时,您就发现了一个真正的问题。

答案 1 :(得分:2)

在测试中添加以下行:

System.out.println("sub_a = " + sub_a);
System.out.println("sub_b = " + sub_b);

结论:

1)sub_a是相对路径,sub_b是绝对路径。

2)exists()不使用绝对路径

3)设置环境变量user.dir不会更改exists()

使用的当前用户目录

4)getAbsolutePath使用user.dir变量而不是真实的当前用户目录!至少对于Windows(请参阅Win32FileSystem.getuserPath)。那就是问题所在! (错误?)

答案 2 :(得分:1)

File可以表示抽象路径。为File创建tmp,从tmp的绝对路径创建一个File将不等于/full/path/to个对象,尽管它们的绝对路径相等。

我不确定sub_a不存在的情况但sub_b会但我怀疑它是分隔符问题。我怀疑它与javadoc for File(File,String)

中的这句话有关
  

将每个路径名字符串转换为抽象路径名,并根据父路径解析子抽象路径名。

我不知道基于Unix的文件系统的情况,在./tmp/sub/full/path/to/tmp内,File不存在。

如果系统之间的问题是一致的,可以通过转储每个{{1}}对象的状态而不仅仅是打印比较来更清楚地理解它。

答案 3 :(得分:0)

在这一行:

File sub_b = new File(root.getAbsolutePath()+"/sub");

您应该使用常量File.separator(取决于底层系统)而不是硬编码的正斜杠。

答案 4 :(得分:0)

我认为这是目录分隔符,因为Windows通常使用反斜杠“\”而Linux使用普通斜杠“/”。

尝试将该行更改为:

File sub_b = new File(root.getAbsolutePath() + System.getProperty("file.separator") + "sub");

答案 5 :(得分:0)

这可能是文件分隔符问题。在Windows上,标准文件分隔符是反斜杠(\)。创建sub_b时,您创建一个包含斜杠和反斜杠的路径名(作为String)。系统可能会对此感到困惑。

答案 6 :(得分:0)

这些结果应该是跨机器的确定性的。让我逐行打破这个:

System.out.println("sub_a exists ? "+sub_a.exists());

在这里,您要问的是文件系统中是否存在此文件。假设文件存在,这应始终返回相同的内容。

System.out.println("sub_b exists ? "+sub_b.exists());

同样的事情。您正在检查此文件是否确实存在。

System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath())));

在这里,您将看到 AbsolutePath 是否相同。

System.out.println("Obj equals ? "+ (sub_a.equals(sub_b)));

在这里,你正在与.equals()进行对象比较,后者会调用FileSystem类来执行两个对象的路径对象的compare(),而不是它们的< EM> AbsolutePath

可能是文件分隔符错误。尝试在构造sub_b时替换File.separator,如下所示:

File sub_b = new File(root.getAbsolutePath()+File.separator+"sub");