如果 需要一个 大小为 1GB 的测试文件来对磁盘进行基准测试、将分区填充至特定阈值或模拟大型日志文件,但是’touch’命令生成的却是一个大小为零的空文件,对上述任何需求都毫无用处。

真正能够实现这个功能的工具共有三个:dd、fallocate 和 truncate。大多数人要么不知道这三个工具的存在,要么不清楚在特定场景下应当选用哪一个。

尽管这些工具解决的是同一个问题,但所采用的方式却截然不同;具体应选用哪一种方式,则取决于想要达成的具体目标。

  • dd 命令:会逐字节地写入实际数据,因此只有当文件完全写入磁盘后,才会重新获得命令行提示符
  • fallocate 命令:会通知文件系统预留空间,但完全不写入任何数据;正因如此,即使是大小以千兆字节(GB)计的文件,该操作也能几乎瞬间完成
  • truncate 命令:仅在文件元数据中设定文件大小,从而创建一个”稀疏文件”(sparse file),即不实际分配任何磁盘块;这使其成为这三种方法中速度最快的,但也正因如此,它无法用于磁盘性能基准测试

以上这三个命令在任何现代 Linux 系统上都是可以直接使用的,具有一定的了解价值。

1] 使用 dd 命令创建大文件

dd 命令是 Unix 和 Linux 系统中一个历史悠久的实用工具,用于底层数据复制。它会从输入源读取数据,然后逐块写入输出文件,因此非常适合按需创建包含实际数据的文件。

一个常见的例子是使用”/dev/zero”,它会持续输出空字节:

# dd if=/dev/zero of=testfile.img bs=1M count=100

典型输出如下:

图.1 使用 dd 命令创建特定大小文件

命令解释如下:

  • if=/dev/zero:从’零设备’(zero device)读取数据,该设备会产生源源不断的空字节流
  • of=testfile.img:将数据写入想要创建的输出文件
  • bs=1M:将块大小设置为 1 兆字节(1MB),即每次读/写操作处理 1MB 数据
  • count=100:指示 dd 命令精确复制 100 个数据块,最终生成 100 × 1MB = 100MB 的文件

命令的输出结果会准确显示写入的字节数以及传输速度,仅凭这一点,它就已经可以作为一项简易的磁盘性能基准测试了。需要注意的是,该文件在磁盘上占用的是实实在在的数据空间而非预留空间,因此实际写入这 100MB 数据到存储介质上需要耗费多少时间,整个过程就会持续多久。

若要创建一个 1GB 的文件,可以使用以下命令:

# dd if=/dev/zero of=testfile.img bs=1M count=1024

也可以简化块数量,则使用如下命令:

# dd if=/dev/zero of=testfile.img bs=1G count=1

对于比较大的文件,则可以添加’status=progress’参数,有助于实时监控进度:

# dd if=/dev/zero of=bigfile.img bs=1M count=4096 status=progress

2] 使用 fallocate 命令快速创建大文件

fallocate 命令工作在文件系统级别而非数据级别,因此当您需要立即分配一个大文件且无需关心文件内容时,它是理想之选。

在 ext4、xfs 和 btrfs 文件系统上,由于 fallocate 会更新元数据而非实际写入内容,因此它会在极短时间内预分配磁盘块。

要立即创建一个 1GB 的文件,可以使用 fallocate 命令,并添加 -l 参数来设置要分配的文件大小,并使用 K、M、G 或 T 作为大小后缀。

# fallocate -l 1G largefile.img

使用以下方法验证文件是否以正确的大小创建:

# ls -lh largefile.img

输出为:

图.2 查看创建文件大小

这 1.0G 表示文件系统已为该文件预留了 1GB 的空间。关键在于理解,对于文件系统而言,该文件虽然占用了实际的磁盘空间,但数据块尚未写入。如果另一个进程尝试写入该空间,文件系统会知道它已被占用。

如果看到”fallocate: fallocate failed: Operation not supported”的错误信息,则说明使用的文件系统不支持预分配,例如 tmpfs 或较旧的 FAT 卷。在这种情况下,可以使用 dd 命令。

3] 使用 truncate 命令立即创建大文件

truncate 命令是这三个命令中最快的,因为它完全不写入数据或预留磁盘空间–它只是在文件系统元数据中设置文件大小,从而创建一个所谓的稀疏文件。

要创建一个 1GB 的稀疏文件:

# truncate -s 1G sparsefile.img

其中’-s’标志用于设置大小,与 fallocate 类似,它接受 K、M、G 和 T 容量后缀。但 truncate 与 fallocate 的行为有所不同。

如果使用 du 命令检查实际磁盘使用情况:

# du -sh sparsefile.img

会看到如下输出:

图.3 使用 du 命令查看稀疏文件大小

可以看到,文件的磁盘占用为零字节。文件大小仅包含元数据,因此只有在实际写入文件时才会分配数据块。这使得 truncate 不适用于磁盘基准测试或交换文件,但非常适合占位符文件、测试用例,或任何只需要特定大小的文件而无需关心其内容的场景。

truncate 的真正优势在于调整现有文件的大小。它可以增大或缩小文件而不重写它,这是 dd 和 fallocate 都无法顺利完成的:

/* 增加文件大小 */
# truncate -s +500M sparsefile.img

/* 收缩文件至特定大小 */
# truncate -s 200M sparsefile.img

重要提示:使用 truncate 缩减文件大小时,位于新大小边界之后的数据会被静默丢弃,且不发出任何警告;因此,在处理包含实际内容的文件时,请务必谨慎使用此命令。

4] 确定文件确切大小

无论是使用哪种工具创建文件,”ls -lh”都能显示易于人类阅读的文件大小;但若要进行字节级的精确验证,则应选用 du 或 stat 命令,因为 ls 会对大小进行取整,而 du 报告的则是实际的磁盘分配空间。

例如命令 stat 命令:

# stat largefile.img

图.4 使用 stat 命令显示文件信息

Size 字段显示了确切的字节数,而 Blocks 字段则告知磁盘上实际分配了多少个 512 字节的数据块。

  • 对于通过 fallocate 创建的文件,这些数据块处于预留状态
  • 对于通过 dd 创建的文件,这些数据块中包含了写入的数据
  • 对于通过 truncate 创建的文件,”Blocks”字段将显示为 0 或接近于 0,因为实际上并未分配任何数据块

现在,本教程已经演示了 3 种在 Linux 中创建指定大小文件的可靠方法;更重要的是,也强调了在何种场景下应当选用哪一种方法。

  • dd 命令通过逐块写入的方式向磁盘写入实际数据,因此非常适用于存储性能基准测试、创建填充零值的磁盘镜像、构建交换文件(Swap files),以及那些对文件系统兼容性有严格要求的场景
  • fallocate 命令的工作原理截然不同:它通过文件系统层直接预留磁盘空间,而无需写入实际数据。这使得它在创建大型占位符文件、虚拟机(VM)磁盘镜像,以及那些对文件内容无特殊要求的测试文件时,能够实现显著的提速
  • truncate 命令则完全跳过了上述两种操作,仅通过修改元数据来设定文件大小。这种方式虽然能实现文件的”瞬时”创建,但生成的是稀疏文件(Sparse file)–这意味着在实际向文件中写入数据之前,系统并不会真正地在磁盘上分配存储空间。

理解这三者差异的最简单方法,莫过于在自己的系统上亲自运行并测试一下这些命令。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注