fallocate -l 1g /tmp/zero.bin 是最快方式,不写磁盘、不占i/o、纯元数据操作;仅限ext4/xfs/btrfs等支持fallocate()的文件系统,失败时需fallback为truncate或dd。

用 fallocate 一秒生成 1GB 零文件,但 Linux 才有
直接结论:fallocate -l 1G /tmp/zero.bin 是最快方式,不写磁盘数据、不占 I/O、不触发页面分配,纯元数据操作。但它只在支持 fallocate() 系统调用的文件系统上有效(ext4/xfs/btrfs 常见,NTFS 或网络文件系统大概率失败)。
常见错误现象:fallocate: Operation not supported —— 别硬扛,换方案;File too large —— 检查 ulimit -f,不是磁盘空间问题。
- 必须用绝对路径,
fallocate不接受相对路径 -
-l后单位支持G/M/K,但别写1GB(会报错),只写1G - 生成的文件是“空洞文件”(sparse file),
ls -lh显示 1G,du -h可能显示 0,读取时内核按需返回零字节
跨平台 fallback:用 truncate + dd 组合保底
truncate 和 fallocate 行为相似,但更兼容(POSIX 工具),它也能快速扩展文件长度,且不写实际数据;不过某些旧版 truncate(如 macOS 的)不支持稀疏扩展,这时得靠 dd。
使用场景:CI 流水线要兼容 macOS/Linux,或目标机器不确定内核版本。
-
truncate -s 1G /tmp/zero.bin—— 大部分 Linux 成功,macOS 默认创建真实 1G 占用(注意磁盘空间) - macOS 安全做法:
dd if=/dev/zero of=/tmp/zero.bin bs=1M count=1024,bs=1M比bs=1快百倍以上 - 别用
dd if=/dev/zero of=... bs=1G—— 内存可能爆掉,dd会尝试分配整块缓冲区
C++ 里调 fallocate?别自己封装,用 posix_fallocate
想在 C++ 程序里生成大零文件?别手撸 open+lseek+write,那会真写 1GB 数据,慢且伤 SSD。POSIX 标准提供了 posix_fallocate,语义和命令行 fallocate 一致,失败时返回错误码而非设置 errno。
性能影响:成功调用后,后续对文件任意偏移的读操作都会返回零,且不会触发写入;比 memset+write 快两个数量级。
- 头文件:
#include <fcntl.h></fcntl.h> - 调用前必须
open(..., O_RDWR | O_CREAT),只读打开会失败 - 返回值非 0 表示失败,常见
ENOTSUP(文件系统不支持)、EINVAL(offset/len 越界) - Windows 没这函数,
_chsize_s或SetFilePointerEx+SetEndOfFile只能扩展,但不会保证内容为零
为什么不用 std::ofstream 写 1GB 零?因为真的慢
有人试过 ofstream.write("\0", 1) 循环 10^9 次?别。哪怕加了 rdbuf()->pubsetbuf,底层仍是系统调用叠加,glibc 还可能做额外校验。实测:1GB 零文件,fallocate 耗时 ≈ 0.002s,dd ≈ 0.3s,C++ write 循环 ≈ 8s+(取决于缓存策略和磁盘)。
容易踩的坑:ofstream 默认不支持跳过中间位置写,seekp 到 1GB 后再 write,文件大小确实变大,但中间全是未定义内容(不是零),而且首次写入前的区域读出来是随机垃圾。
- 如果非要用 C++ 流,至少先
truncate或fallocate扩展,再用ofstream覆盖局部(比如打日志头) -
std::ios_base::binary必须设,否则 Windows 下\n会被转成\r\n,破坏零填充 - 别信“C++17 filesystem::resize_file”,它底层就是
truncate或ftruncate,行为一致,但不保证内容为零
真正麻烦的从来不是“怎么生成”,而是生成之后——你得确认读出来的每个字节确实是零,尤其当文件被 mmap、被多个进程读、或落在不同文件系统上时。空洞文件在某些容器或备份工具里会被“填实”,这时候 du 和 ls 就不再相等了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











