在Java中,File.exists()的替代方法

10
我从来没想到会发生在我身上,但我遇到了我在Java中的第一个bug。

https://bugs.java.com/bugdatabase/view_bug?bug_id=5003595

我基本上和描述中的bug(在Linux上的NFS)处于完全相同的情况,我发现File.exists()并没有立即返回正确的值。
所以我的问题是,有没有其他方法来检查文件是否存在?如果可能的话,我希望保持操作系统无关。
编辑:我找到了一个解决方法。如果你调用ls $filedir,NFS会刷新给Java带来麻烦的缓存/元数据,然后File.exists()会返回正确的值。当然,这并不完全理想,因为它会影响可移植性,但是有办法解决这个问题。

这是什么类型的文件?你是在寻找特定类型的文件还是任何类型的文件?你可以运行System.exec("ls")并解析结果以获取你想要的文件。虽然我相信有更简单的方法,但我会将其作为注释留下。 - Falmarri
这个 bug 是特定于 Java 1.4.2_03 的,该版本已经在多年前结束了其支持生命周期。出于好奇,为什么不迁移到 Java 5 或更高版本呢?您是否尝试使用受支持的 JRE 进行测试,以查看是否会出现任何问题? - Steve Perkins
2
@Steve:我正在运行Java 6。我假设由于他们在这个错误上标记了“不会修复”,所以它在任何版本的Java中都没有被修复。至少,这是我的应用程序表现告诉我的。 - Ben
1
很奇怪。我同意下面Ben的观点,即File.exists()可能会报告错误的正面结果(即在文件不存在时说它存在)。然而,错误的负面结果是不同的(即说文件不存在,但实际上它就在那里)。那个错误报告已经有6年之久了,评论表明他们正在JSR 203的开发中解决这个问题...所以如果你仍然在当代JRE中看到这个问题,我建议你提交一个新的错误报告。然而,下面的两个答案基本上是正确的...最好的解决方法就是使用try-catch块。 - Steve Perkins
6个回答

7

我也遇到过同样的问题,用file.getParentFile().list()来解决了。本质上和你的解决方案相同,但是对操作系统没有限制。


@SteveCohen 这可能会破坏正在被查看的任何缓存。这意味着也会带来性能损失。 - Alkanshel

7

您在使用NFS时可能会遇到的一个基本问题是它缓存属性、文件和目录信息,这意味着信息可能会过时。尽管您可以关闭缓存,但这会导致性能显著降低。

需要记住的重要事项是:NFS不是消息传递服务,也不是为及时传输数据而设计的。


1
这大概是我能标记的最接近的答案了。问题实际上更接近于使用了NFS。在我的情况下,一个名为x.file的文件被创建,然后被删除,然后再次用相同的名称(x.file)创建。重新创建后,对该文件进行stat调用会声称它不存在。在整个目录上调用“ls”似乎可以刷新缓存并解决Java的file.exists()问题,并且对stat的调用也开始正确返回。这似乎表明问题更多地与NFS有关,而不是Java。 - Ben

6
如果File.exists()返回true,然后有人删除了文件/您的NFS挂载消失,那么您尝试打开文件会发生什么?基本上,File.exists()是无用的,因为您需要处理可能由于打开文件而引起的异常。

5

File.exists 只能告诉你文件之前是否存在过。它无法告诉你以下信息:

  • 当你尝试打开这个文件时,它是否会存在
  • 你是否有权限打开它
  • 实际上没有提供任何有用的信息

因此,设计你的应用程序时请考虑到可以处理不存在的文件,而不是事先检查它们是否存在。(在实际使用文件时,必须处理各种异常情况。)


1
你假设我以后会打开文件,但在我的特定情况下这并不正确。实际上,在我的应用程序中,我根本不会打开该文件;我只是出于其他原因检查其是否存在。 - Ben

4
我注意到Java 7的java.nio.file.Path.exists()方法会返回false,如果文件不存在或者无法确定其存在性。因此,看起来假阴性还将存在一段时间,你的代码需要容忍它们。

2
明显的替代方法是使用 File.isFile()。首先尝试这个。
虽然在读取只读文件时它会变得不准确,但您始终可以使用 File.canWrite() 来检查文件是否存在。
如果上述两种方法都失败了,您可以使用 File.length()。如果它返回 0L,则说明该文件不存在。

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