稀疏文件

来自 ArchWiki

根据维基百科,稀疏文件是一种文件类型,当分配给文件的块大部分为空时,它尝试更有效地利用文件系统空间。 这是通过将表示空块的简要信息(元数据)写入磁盘,而不是构成该块的实际“空”空间,从而使用更少的磁盘空间来实现的。 只有当块包含“真实”(非空)数据时,完整块大小才作为实际大小写入磁盘。

读取稀疏文件时,文件系统会透明地将表示空块的元数据转换为在运行时填充零字节的“真实”块。 应用程序不会意识到这种转换。

大多数现代文件系统都支持稀疏文件,包括大多数 Unix 变体和 NTFS,但值得注意的是 Apple 的 HFS+ 不支持。 稀疏文件通常用于磁盘镜像(不要与稀疏镜像混淆)、数据库快照、日志文件和科学应用中。

稀疏文件的优点是仅在实际需要时才分配存储空间:节省了磁盘空间,即使文件系统上没有足够的可用空间也可以创建大型文件。

缺点是稀疏文件可能会变得碎片化; 文件系统可用空间报告可能具有误导性; 填满包含稀疏文件的文件系统可能会产生意想不到的影响; 以及使用不支持稀疏文件的程序复制稀疏文件可能会复制整个文件,包括未显式存储在磁盘上的空块,这会浪费文件的稀疏属性的优势。

创建稀疏文件

truncate 实用程序可以创建稀疏文件。 此命令创建一个 512 MiB 的稀疏文件

$ truncate -s 512M file.img

dd 实用程序也可以使用,例如

$ dd if=/dev/zero of=file.img bs=1 count=0 seek=512M

稀疏文件具有不同的表观文件大小(它们可能扩展到的最大大小)和实际文件大小(为磁盘上的数据分配了多少空间)。 要检查文件的表观大小,只需运行

$ du -h --apparent-size file.img
512M    file.img

并且,要检查文件在磁盘上的实际大小

$ du -h file.img
0       file.img

如您所见,尽管文件的表观大小为 512 MiB,但其“实际”大小实际上为零——这是因为由于稀疏文件的性质和优点,它将“任意扩展”以最大限度地减少存储其内容所需的空间。

将现有文件转换为稀疏文件

fallocate 实用程序可以在受支持的文件系统上将现有文件转换为稀疏文件

$ fallocate -d copy.img
$ du -h copy.img
0       copy.img

将现有文件转换为非稀疏文件

以下命令创建(稀疏)文件的非稀疏副本

$ cp file.img copy.img --sparse=never
$ du -h copy.img 
512M    copy.img

在稀疏文件中创建文件系统

本文或本节需要改进语言、wiki 语法或风格。 请参阅Help:Style以获取参考。

原因: 稀疏文件不必包含文件系统,应解释其目的。 (在Talk:Sparse file中讨论)

现在我们已经创建了一个稀疏文件,是时候使用文件系统对其进行格式化了。 例如,ext4

$ mkfs.ext4 file.img

我们现在可以检查它的大小,看看文件系统如何影响它

$ du -h --apparent-size file.img
512M    file.img
$ du -h file.img
456K     file.img

正如您可能预料到的那样,使用文件系统对其进行格式化会增加它的实际大小,但保持其表观大小不变。 现在我们可以创建一个目录,我们将用它来挂载我们的文件

# mount --mkdir -o loop file.img mountpoint

哒哒! 我们现在既有一个文件,又有一个文件夹,我们可以在其中存储几乎 512 MiB 的信息!

在启动时挂载文件

要在启动时自动挂载稀疏镜像,请将条目添加到您的 fstab

/path/to/file.img  /path/to/mountpoint  ext4  loop,defaults  0  0
注意: 务必包含 loop 选项,否则将无法挂载。

检测稀疏文件

由于稀疏文件占用的块少于表观文件大小所需的块,因此可以通过比较两个大小来检测它们。 如果文件系统使用压缩、扩展属性占用空间差异、文件在内部碎片化、具有间接块以及类似情况,则这不是一种万无一失的方法。 尽管如此,标准检查方法仍然是

$ ls -ls sparse-file.bin

如果文件大小大于第一列中的分配大小,则该文件是稀疏文件。 使用 du 并通过比较也可以实现相同的目的

$ du sparse-file.bin
$ du --apparent-size sparse-file.bin

更进一步是使用 find 打印稀疏性

$ find sparse-file.bin -printf '%S\t%p\n'

稀疏文件的稀疏性值小于 1,而普通文件的稀疏性值正好为 1 或略高于 1。 上面的命令可以很容易地扩展为列出所需路径中的稀疏文件

$ find path/ -type f -printf '%S\t%p\n' | gawk '$1 < 1.0 {print}' | cut -f '2-'

复制稀疏文件

使用 cp 复制

通常,cp 擅长检测文件是否为稀疏文件,因此运行以下命令就足够了

$ cp file.img new_file.img

然后 new_file.img 将是稀疏文件。 但是,cp 确实有一个 --sparse=when 选项。 如果稀疏文件不知何故变成了非稀疏文件(即,空块已完整写入磁盘),这将特别有用。 可以通过以下方式恢复磁盘空间

$ cp --sparse=always new_file.img recovered_file.img

使用 tar 归档

本文或本节需要改进语言、wiki 语法或风格。 请参阅Help:Style以获取参考。

原因: 非正式写作,请参阅 Help:Style#Language register。 (在Talk:Sparse file中讨论)

有一天,您可能决定备份您珍爱的稀疏文件,并为此目的选择 tar 实用程序; 但是,您很快意识到您遇到了问题

$ du -h file.img
33M     file.img
$ tar -cf file.tar file.img
$ du -h file.tar
513M    file.tar

显然,即使稀疏文件的当前大小仅为 33 MB,使用 tar 归档它也会创建一个文件完整大小的归档文件! 不过幸运的是,tar 有一个 `--sparse' (`-S') 标志,当与 `--create' (`-c') 操作结合使用时,会在归档时测试所有文件的稀疏性。 如果 tar 发现文件是稀疏的,它会在归档文件中使用该文件的稀疏表示。 这在归档可能包含许多空值的文件(例如 dbm 文件)时非常有用,并且可以显着减少存储此类归档文件所需的空间量。

$ tar -Scf file.tar file.img
$ du -h file.tar
12K     file.tar

调整稀疏文件大小

本文或本节需要改进语言、wiki 语法或风格。 请参阅Help:Style以获取参考。

原因: 依赖于#在稀疏文件中创建文件系统并不明显,并非每个稀疏文件都包含文件系统。 另外写作过于非正式,请参阅 Help:Style#Language register。 (在Talk:Sparse file中讨论)

在我们调整稀疏文件大小之前,让我们用几个小文件填充它以进行测试

$ for f in {1..5}; do touch folder/file${f}; done
$ ls folder/
file1  file2  file3  file4  file5

现在,让我们向其中一个文件添加一些内容

$ echo "This is a test to see if it works..." >> folder/file1
$ cat folder/file1
This is a test to see if it works...

增大文件

如果您需要增大文件,您可以执行以下操作

# umount folder
$ dd if=/dev/zero of=file.img bs=1 count=0 seek=1G
0+0 records in
0+0 records out
0 bytes (0 B) copied, 2.2978e-05 s, 0.0 kB/s

这将将其大小增加到 1 GiB 并保持其信息完整。 接下来,我们需要增加其文件系统的大小

$ e2fsck -f file.img
$ resize2fs file.img
resize2fs 1.47.1 (20-May-2024)
Resizing the filesystem on file.img to 262144 (4k) blocks.
The filesystem on file.img is now 262144 (4k) blocks long.

...然后,重新挂载它

# mount -o loop file.img folder

检查其大小会得到

# du -h --apparent-size file.img
1.0G    file.img
# du -h file.img
564K     file.img

...以及检查一致性

# df -h folder
Filesystem            Size  Used Avail Use% Mounted on
/tmp/file.img         1.0G   33M  992M   4% /tmp/folder
# ls folder
file1  file2  file3  file4  file5
# cat folder/file1
This is a test to see if it works...

工具

  • sparse-fio — 类似于 dd 的程序,用于处理稀疏填充非零数据的文件
https://github.com/anyc/sparse-fio || sparse-fio-gitAUR
  • sparseutils — 用于处理稀疏填充文件的实用程序,提供 mksparsesparsemap,可以使用 pip 安装
https://pypi.ac.cn/project/sparseutils/ || 未打包? 在 AUR 中搜索

参见