跳转至内容

稀疏文件

来自 ArchWiki

根据 Wikipedia 的说法,稀疏文件是一种文件类型,它在文件分配的块大部分为空时,试图更有效地使用文件系统空间。这是通过将代表空块的简短信息(元数据)写入磁盘,而不是写入构成块的实际“空”空间来实现的,从而减少磁盘空间使用。只有当块包含“真实”(非空)数据时,整个块大小才会被写入磁盘作为实际大小。

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

大多数现代 文件系统 都支持稀疏文件,包括大多数 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'

稀疏文件的稀疏度值小于一,而普通文件则正好为一或略高于一。上面的命令可以轻松扩展以列出所需路径中的稀疏文件

$ 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 发现文件是稀疏的,它会在存档中使用文件的稀疏表示。这对于归档可能包含许多 null 的文件(如 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 中搜索

参见