用 fwrite 批量写入替代 std::ofstream

用 fwrite 配合缓冲区批量写入,别用 std::ofstream
直接用 std::ofstream 逐字节或逐行写,1GB 文件可能跑十几分钟;fwrite 批量写入能压到几秒内。核心是绕过 C++ iostream 的格式化开销和频繁 syscall,让数据以原始二进制块直通磁盘。
- 每次写入至少
64KB(65536字节),太小会抵消批量优势;1MB是更稳妥的起点 - 用
std::vector<uint8_t></uint8_t>预分配缓冲区,填满后一次性fwrite,避免new/delete频繁抖动 - 不要用
std::rand()填充——它慢且周期短;改用std::mt19937+std::uniform_int_distribution<uint8_t></uint8_t>,但注意:只初始化一次引擎,别在循环里反复构造 - 文件打开必须用
"wb"模式(C 风格)或std::ios::binary | std::ios::out(C++ 风格),否则 Windows 下换行符会被悄悄替换,大小不准
生成 1GB 要精确控制字节数,别靠循环次数估算
1GB = 1073741824 字节(即 1 ),不是 <code>1000*1000*1000。用近似循环次数(比如“写 100 万次 1KB”)极易偏差几百 MB,尤其当缓冲区大小不能整除总长度时。
- 计算完整写入次数:
full_writes = total_size / buffer_size - 剩余字节数:
remainder = total_size % buffer_size - 先循环
full_writes次写满缓冲区,再单独处理remainder字节(用fwrite(buf, 1, remainder, fp)) - 务必用
fseek(fp, 0, SEEK_END)+ftell(fp)或stat()校验最终文件大小,CI 环境或某些文件系统(如 exFAT)可能延迟落盘
Windows 下注意 _setmode(_fileno(fp), _O_BINARY)
即使开了 "wb",MSVC CRT 在某些配置下仍可能对 FILE* 默认启用文本模式,导致写入 0x0A 时自动转成 0x0D 0x0A,文件瞬间变大且内容错乱。
- 调用
fopen后立刻加_setmode(_fileno(fp), _O_BINARY)(仅 Windows) - Linux/macOS 不需要,但加了也无害(宏定义为空)
- 若用
std::ofstream,则无需此步——但你本就不该用它(见第一条)
内存够就全塞进 std::vector,不够就分块生成
1GB 数据全 load 到内存再写,对多数现代机器(16GB+ RAM)是最快路径;但若内存紧张(比如嵌入式或容器限制),必须流式生成——此时随机性会受限于 PRNG 状态复用。
- 全内存方案:分配
std::vector<uint8_t>(1073741824)</uint8_t>,用单个std::mt19937实例填充,再fwrite(vec.data(), 1, vec.size(), fp) - 流式方案:每块用相同种子初始化
std::mt19937(如mt19937{seed + chunk_idx}),保证各块独立可重现,但别用时间戳当种子——会导致块间重复 - 绝对不要在循环里 new/delete 缓冲区;用一个 vector.resize() 复用内存
最易被忽略的是:关掉 stdout/stderr 的同步(std::ios_base::sync_with_stdio(false))没用——因为你根本不该用 iostream 写这个文件。真要快,从 fopen 到 fwrite 就一条直线,中间别拐弯。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











