为什么Files.deleteIfExists对于大型文件要花这么长时间?

时间:2019-10-22 09:56:28

标签: java java-io

在大文件(此处为35GB)上:

Files.deleteIfExists(Path.get("large.csv"));

使用java进行删除需要60秒以上的时间。在控制台上用rm large.csv删除片刻。

为什么?我可以加快从Java内部删除大型文件的速度吗?

1 个答案:

答案 0 :(得分:6)

我将此归咎于操作系统。在Windows和Linux上,Java只需调用操作系统提供的C本机运行时库提供的方法来删除文件。

(检查OpenJDK源代码。)


那为什么操作系统删除大型文件会花很长时间?

  • 典型的文件系统会保留空闲和使用中的磁盘块的映射。如果要释放一个非常大的文件,则会释放大量块,因此需要更新空闲映射中的大量位并将其写入磁盘。

  • 典型的文件系统使用基于树的索引结构来将文件偏移量映射到磁盘块。如果文件足够大,则索引结构可能会跨越多个磁盘块。删除文件后,需要扫描整个索引以找出包含需要释放的数据的所有块。

  • 如果文件碎片很严重,并且索引块和可用的映射块分散很多,则这些成本会放大。

  • 删除文件通常是同步完成的。至少,在系统调用返回之前,所有磁盘块都被标记为空闲。 (如果您不这样做,则用户可能会抱怨删除文件​​不起作用。)

简而言之,当删除一个大文件时,有很多“磁盘” I / O要做。操作系统执行此操作,而不是Java。


那么为什么从命令行删除文件会更快呢?

一个可能的原因是,您使用的rm命令实际上只是将已删除的文件移动到“废纸folder”文件夹中。这实际上是一个 rename 操作,它比真正的删除要快得多。

注意:这不是Linux上rm的正常行为。

另一个可能的原因(在Linux上)是,要删除的文件的索引和空闲映射块在一个测试方案中位于缓冲区高速缓存中,而在另一种测试方案中则不在。 (如果您的计算机丢失了多余的RAM,Linux操作系统将在RAM中缓存磁盘块以提高性能。这是非常有效的。)