假设您有一个包含许多空字节\x00 的文件。这些许多空字节\x00 被称为空洞。存储空字节效率不高,我们知道文件中有很多空字节,那么为什么要将它们存储在存储设备上呢?我们可以改为存储描述这些零的元数据。当一个进程读取文件时,这些零字节块会动态生成,而不是存储在物理存储中(查看 Wikipedia 中的此示意图):
这就是稀疏文件高效的原因,因为它不会将零存储在磁盘上,而是保存足够的数据来描述将生成的零。
注意:逻辑文件大小大于稀疏文件的物理文件大小。这是因为我们没有将零物理存储在存储设备上。
编辑:
当你运行时:
$ dd if=/dev/zero of=output bs=1G count=4
此处的命令将 4G 空字节块复制到output。要看到:
$ stat output
File: ouput
Size: 4294967296 Blocks: 8388616 IO Block: 4096 regular file
--omitted--
你可以看到这个文件有8388616块分配给它,这些块只存储从/dev/zero复制的空字节,它们确实占用了物理磁盘空间,它们是存储在磁盘上的孔(稀疏零)。 dd 完成了您的要求,将数据块从一个文件复制到另一个文件。
现在,运行这个命令来检测漏洞并使文件就地稀疏:
$ fallocate -d output
$ stat output
File: swapfile
Size: 4294967296 Blocks: 0 IO Block: 4096 regular file
--omitted--
你注意到什么了吗?现在的块数为 0,因为仅存储空字节的块已被释放。请记住,output 的块不存储任何内容,只有一堆空零,fallocate -d 检测到仅包含空零的块并释放它们,因为该文件的所有块都包含零,所以它们都被释放。
还要注意大小是如何保持不变的。这是文件的逻辑(虚拟)大小,而不是它在磁盘上的大小。知道output 现在不占用物理 存储空间至关重要,它分配了0 个块,因此我并没有真正使用磁盘空间。运行fallocate -d 后保留的大小,因此当您稍后从文件中读取时,您会得到文件系统在运行时为您生成的空字节。然而output 的物理大小为零,它不使用任何数据块。
请记住,当您读取 output 文件时,空字节是由文件系统在运行时动态生成的,它们不是真正物理存储在磁盘上,并且文件的大小由 @987654337 报告@ 是逻辑大小,output 的物理大小为零。在这种情况下,当进程读取文件时,文件系统必须生成 4G 的空字节。
使用dd生成稀疏文件:
$ dd if=/dev/zero of=output2 bs=1G seek=0 count=0
$ stat
stat output2
File: output2
Size: 4294967296 Blocks: 0 IO Block: 4096 regular file
GNU dd 内部使用 lseek 和 ftruncate,所以检查 truncate(2) 和 lseek(2)。