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”系统用于检查文件系统的属性。
知道这个问题可能来自哪里?
答案 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");