ftruncate 是 Linux/macOS 下生成大块全零稀疏文件的最快方案,仅修改 inode 大小字段,毫秒级完成 GB 级文件创建;Windows 需用 SetFilePointerEx + SetEndOfFile,注意权限与 LARGE_INTEGER 使用。

用 ftruncate 扩展文件到指定大小(最轻量)
Linux/macOS 下生成大块全零文件,ftruncate 是最快方案——它不写数据,只改 inode 中的文件大小字段,内核按需用稀疏页填充。毫秒级完成几十 GB 文件创建。
常见错误:先 fopen 再 fseek+fputc,这会真实写入每个字节,慢且耗 I/O。
- 必须用
open(不是fopen),带O_RDWR | O_CREAT标志 - 文件描述符要可写,否则
ftruncate返回EPERM - 目标大小超过当前文件长度才真正扩展;若已更大,
ftruncate会截断(注意数据丢失) - 生成的是稀疏文件,
ls -l显示逻辑大小,du显示实际磁盘占用(通常极小)
int fd = open("zero.bin", O_RDWR | O_CREAT, 0644);
if (fd != -1) {
ftruncate(fd, 1024LL * 1024 * 1024); // 1GB
close(fd);
}
Windows 下用 SetFilePointerEx + SetEndOfFile
Windows 没有直接对应 ftruncate 的 C 标准库函数,得用 Win32 API。核心是把文件指针移到目标偏移,再调 SetEndOfFile 扩展。
容易踩的坑:SetFilePointerEx 的偏移参数是 LARGE_INTEGER*,不能直接传整数;且文件必须以 GENERIC_WRITE 打开,否则 SetEndOfFile 失败并返回 ERROR_ACCESS_DENIED。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
CreateFile必须含GENERIC_WRITE,即使只打算扩展不写内容 - 目标大小超 4GB 时,
LARGE_INTEGER的QuadPart字段必须赋值,别只设LowPart - 扩展后文件内容为零,但磁盘空间不会立即分配(类似稀疏文件),除非后续写入触发
HANDLE h = CreateFileA("zero.bin", GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h != INVALID_HANDLE_VALUE) {
LARGE_INTEGER li;
li.QuadPart = 1024LL * 1024 * 1024; // 1GB
SetFilePointerEx(h, li, nullptr, FILE_BEGIN);
SetEndOfFile(h);
CloseHandle(h);
}
跨平台封装要注意的兼容点
如果代码要同时跑在 Linux 和 Windows 上,别自己写宏判断系统再分别调 API——容易漏掉权限、错误码、大数处理等细节。
更稳妥的做法是:优先用 posix_fallocate(Linux)或 fallocate(glibc ≥ 2.10),它们能真正预分配磁盘空间(非稀疏),避免后续写入时因空间不足失败。但 Windows 不支持,所以仍得 fallback 到上面两套逻辑。
-
posix_fallocate在文件系统不支持时会退化为循环write,性能暴跌,务必检查返回值是否为ENOTSUP - C++ 标准库无跨平台文件截断接口,
std::ofstream的seekp+put无法扩展文件,只会从当前位置覆盖或失败 - 用
std::filesystem::file_size获取大小没问题,但别指望resize_file(C++17)能扩展:它只在实现支持时才有效,GCC libstdc++ 目前完全不支持扩展,仅限截断
为什么不用 dd if=/dev/zero 或 truncate 命令?
命令行工具确实简单,但嵌入到 C++ 程序里调 system("truncate -s 1G zero.bin") 有硬伤:启动 shell 开销大、路径空格和特殊字符要转义、错误码难捕获、无法控制 umask 和原子性。
尤其在高频生成临时占位文件的场景(如测试框架、打包工具),系统调用比 fork+exec 快 100 倍以上,且能精确控制权限和错误分支。
-
truncate命令底层就是调ftruncate,自己调更直接 -
dd默认块大小 512 字节,生成 1GB 文件要发 2097152 次 write 系统调用,纯属自找麻烦 - 如果真要用命令,至少用
posix_spawn替代system,避免 shell 解析风险
生成稀疏文件本身很快,但后续首次写入某块区域时可能触发磁盘分配和清零,这个延迟不可控。如果业务要求“写入即稳定”,就得用 fallocate(2)(Linux)或 FSCTL_SET_ZERO_DATA(Windows)真正预填零——不过那就不是“快速生成”了。


















