稀疏文件
根据 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
在稀疏文件中创建文件系统
现在我们已经创建了一个稀疏文件,是时候用文件系统对其进行格式化了。例如,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 归档
有一天,你可能会决定备份你心爱的稀疏文件,并为此目的选择 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
调整稀疏文件大小
在调整稀疏文件大小之前,让我们填充一些小文件用于测试
$ 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 的程序,用于处理稀疏填充有非零数据的文件
- sparseutils — 用于处理稀疏填充文件的工具,提供
mksparse和sparsemap,可使用 pip 安装