我在 Windows 10 上使用 Java 17。我有一组采用这种形式的目录:
data/dir-0
data/dir-1
data/dir-2
…
data/dir-999
我使用变量
0
对整数 999
到 i
进行循环。在每个循环中,我只是检查子目录中是否有 foo.bar
文件:
Path foobarFile = dataDir.resolve("dir-"+i);
if(Files.exists(fooBarFile)) {
//do something; currently does nothing
}
如果所有
data/dir-*
目录都是空的,它们就会爆炸,整个循环在一瞬间结束(几分之一秒)。
但是,如果某些
data/dir-*
目录包含 foo.bar
文件,则循环会加速遍历空目录,直到真正找到 foo.bar
文件,然后突然每个 exists(fooBarFile)
调用都需要几乎半秒! (每次调用都花费相同的时间,就好像有一些时钟在计数一样。)
然后它变得更奇怪:如果我在没有任何更改的情况下再次运行该程序,它会以某种方式“记住它离开的位置”,并且会加速遍历所有目录,直到到达之前未检查过的目录。然后每个
exists(fooBarFile)
调用几乎需要一秒钟。
请注意,这会在 Eclipse 内和命令行中发生。
为什么文件实际存在时
exists(fooBarFile)
需要这么长时间?它如何“记住”在运行应用程序之间检查了哪些内容?我很困惑。
更新: 显然,这里是 Java 17 如何检查 Windows 路径是否存在,在
sun.nio.fs.WindowsFileSystemProvider.checkReadAccess(WindowsPath file)
中:
try {
Set<OpenOption> opts = Collections.emptySet();
FileChannel fc = WindowsChannelFactory
.newFileChannel(file.getPathForWin32Calls(),
file.getPathForPermissionCheck(), opts, 0L);
fc.close();
} catch (WindowsException exc) {
…
是的,看来 Java 通过打开文件通道来判断文件是否存在! 😦😭
告诉我事实并非如此。我只需要知道文件是否存在,这样我就知道是否需要生成它。我不需要检查读取访问权限或其他任何内容。难道就没有更有效的方法吗?此外,在最近配备 SSD 的机器上,打开和关闭通道肯定不会花费一秒钟的时间,不是吗??
这似乎与 Windows Defender 有关。我转到 Windows 安全中心 > 病毒和威胁防护 > 病毒和威胁防护设置,并将
data
目录添加到排除项中。突然我的程序在所有目录中尖叫。
显然,Java 检查文件是否存在的方法(通过打开文件)与 Windows Defender 相结合,会减慢文件存在检查的速度!
(我刚刚通过删除 Windows Defender 排除来验证了这一点;当我在执行此操作后立即运行它时,循环突然停止了。)
这可不是什么好事。这根本不是什么好事。 Java 和 Windows Defender 似乎都没有做到理想的效果。
(我还注意到,第一次在目录中进行 Maven 构建时,重新启动后速度非常慢,直到我构建了一次项目。我想知道将项目目录添加到 Windows Defender 排除列表中是否会有帮助…)
正如 Luca Scarcia 所建议的那样,
File.exist()
使用了不同的技术,令人惊讶的是,即使没有 Windows Defender 排除,它似乎也能飞过所有目录。
为什么、为什么、为什么 Java 使用这种强力打开文件来检查 Java NIO 是否存在
Files.exists(Path)
?这是个问题。