为啥'File.exists'返回true,即使NIO'Files'类中的'Files.exists'返回false

Posted

技术标签:

【中文标题】为啥\'File.exists\'返回true,即使NIO\'Files\'类中的\'Files.exists\'返回false【英文标题】:Why does 'File.exists' return true, even though 'Files.exists' in the NIO 'Files' class returns false为什么'File.exists'返回true,即使NIO'Files'类中的'Files.exists'返回false 【发布时间】:2015-08-11 18:22:01 【问题描述】:

我正在尝试确定网络文件夹中是否存在文件:

// File name is "\\QWERTY\folder\dir\A123456.TXT"
Path path = Paths.get("\\\\QWERTY\\folder\\dir\\A123456.TXT")

使用蔚来Files:

Files.exists(path) == false

使用File

path.toFile().exists() == true

根据我们的测试,使用File 似乎是正确的。为什么FileFiles 工作得更好?

那么,它是什么?不能两者兼得!

等等,还有Files.notExists(path)

网络共享文件实际存在时

Files.exists(path): false
Files.notExists(path): false
path.toFile().exists(): true

什么时候网络共享文件确实存在

Files.exists(path): false
Files.notExists(path): true
path.toFile().exists(): false

查看上述三个结果的另一种同样疯狂的方式

boolean exists = Files.exists(path) || !Files.notExists(path)
boolean notExists = Files.notExists(path) || !Files.exists(path)
boolean oldFashionedExists = path.toFile().exists()

:笑脸:

环境与评论

程序在 Windows 8.1 Pro 32 位机器(操作系统和机器)上运行,并检查来自 Windows 2008 R2(32 位)机器的网络共享。

为了确定 Files.exists 失败,我安装了一个 WatchService 来监视文件夹,并在 Files.exists 检查时看到该文件确实存在。然后我以两种方法登录,发现 File.exists 是正确的。

现在,在我的代码中,我的支票是Files.exists(path) || path.toFile().exists()

两者都做似乎有点愚蠢。可能以后就可以逍遥法外了。只是试图让甲骨文的工程师受益于怀疑,但整个事情都是相当愚蠢的,他们报告的不同。

另外,我不在乎“存在”是否立即过时。我只想知道文件在我们检查的那一刻是否存在。我从来没有遇到过这种情况——我们只是在我和另一位开发人员之间花了 30 个小时试图弄清楚为什么我们的程序因为这个“功能”而没有接口。

沉思一下

File.exists():返回真当且仅当此抽象路径名表示的文件或目录存在时;否则为假。

Files.exists():如果文件存在则返回true;如果文件不存在或无法确定其存在,则为 false。

这让我崩溃了! “当且仅当此抽象路径名表示的文件或目录存在;否则为假”与“如果文件存在则为真;如果文件不存在或无法确定其存在则为假”不一致。

那么,如果“无法确定存在”,File.exists 怎么可能是真的呢?显然,存在可以(并且正在)由 File 而不是由 Files 确定。

【问题讨论】:

Fils.exists 文档:Note that the result of this method is immediately outdated. If this method indicates the file exists then there is no guarantee that a subsequence access will succeed. Care should be taken when using this method in security sensitive applications.。这可能是问题所在,尤其是在网络上。 @user1803551,我很确定另一个人也是如此,在 either 情况下不能保证有人不会在您的支票和尝试使用。 你可以试试Files.notExists,看看你得到了什么结果? 小心 UNC 路径,遇到了很多麻烦,尤其是在 Windows 8 上 “那么,如果“无法确定存在”,File.exists 怎么可能是真的呢?显然,存在可以(并且正在)由 File 而不是由 Files 确定。 " File.exists() 方法仅适用于File 实例,它表示文件系统上的资源。 Files.exists(Path)Path 实例一起使用,它可以捕获(取决于可用的 FileSystemProviders)不在文件系统中的东西。 【参考方案1】:

我遇到了同样的问题,但你的 hack 对我没有帮助。当文件实际存在时,所有方法都返回错误:

Files.exists(path) = false, 
path.toFile().exists() = false, 
Files.notExists(path) = true, 
Files.exists(path) || path.toFile().exists() = false

但是,如果此时在资源管理器中打开了包含此文件的网络目录,则正确处理了它的存在

我通过在目录中创建一个新文件(然后删除它)解决了这个问题:

Files.createFile(Paths.get(path.getParent().toString(), "test"));

显然,在该命令之后,Windows 会更新有关文件夹的信息

【讨论】:

【参考方案2】:

至于为什么两者之间可能存在差异,请对比他们的文档:

File.exists():当且仅当此抽象路径名表示的文件或目录存在时返回 true;否则为假。

Files.exists():如果文件存在则返回true;如果文件不存在或无法确定其存在,则为 false。

这可以可能解释两者之间的区别,也许Files 无法确定文件的存在。

例如,在 Linux 下,可以设置目录和文件权限,这样您就可以打开一个存在但无法看到它存在的文件(通过取消对文件所在的目录,同时保持文件权限更加开放)。

根据more of Oracle's documentation,Files.exists() 仅在验证文件存在时才返回true

false 的返回值 not 表示它不存在。

他们建议您同时使用exists()notExists() 来涵盖这三种可能性,例如:

if (Files.exists(fspec)) 
    System.out.println("It exists!");
else if (Files.notExists(fspec)) 
    System.out.println("It does not exist!");
else
    System.out.println("I have no idea!");

这涵盖了上述链接中涵盖的文件状态的三种可能性:

文件已验证存在。 该文件已验证不存在。 文件的状态未知。当程序无权访问该文件时,可能会出现此结果。

【讨论】:

其实,在我的代码中是正确的,我只是在示例中输入错误。感谢您发现这一点。已更正。 那为什么File#exists 会返回true?文档指定“真正的当且仅当此抽象路径名表示的文件或目录存在;” 因此我的措辞“可能会或可能不会”。 @Jean-FrançoisSavard 哈哈。这就是我发布问题的原因。现在我正在使用 'Files.exists(path) || 检查所有内容path.toFile().exists()' :) @Saint,由于您现在已经更改了问题以澄清您使用的字符串具有正确的转义符,因此我删除了详细说明问题原因的初始部分。

以上是关于为啥'File.exists'返回true,即使NIO'Files'类中的'Files.exists'返回false的主要内容,如果未能解决你的问题,请参考以下文章

Java:为啥即使路径完整,使用 file.exists() 也会给出错误值?

File.Exists 返回 false,即使我可以看到文件 C#

File.Exists仅在文件名上返回true

文件存在但 java file.exists() 但返回 false

为啥即使我传递了错误的用户名,mysqli_connect() 也会返回 true?

区分大小写的 Directory.Exists / File.Exists