最简单直接的二进制写入是用 vec.data() + write(),但仅限POD类型;非POD(如含std::string)必须序列化;需处理partial write、跨平台文件模式(Windows用"wb")、ABI兼容性及读取验证。

std::vector::data() + write() 一次性写入最简单
直接把 std::vector 底层内存块扔进文件,是最快、最零拷贝的方式。前提是元素类型是 POD(比如 int、float、double、std::array<char></char>),且不包含指针、虚函数、自定义构造/析构。
常见错误现象:write(fd, &vec, sizeof(vec)) —— 这只写了 vector 对象本身(通常 24 字节),不是你想要的数据;或者用 vec.begin() 但忘了转成原始指针,编译不过。
- 正确做法:用
vec.data()获取首地址,配合vec.size() * sizeof(T)算总字节数 - 必须检查
vec.data()是否非空(空 vector 的data()可能为 nullptr,C++11 起保证可调用但不一定有效) - 用
write()(POSIX)或ofstream.write()(C++ stream)都行,但后者默认带缓冲,加.rdbuf()->pubsetbuf(nullptr, 0)可关缓冲(否则小数据可能不落盘)
std::vector<float> v = {/* ...百万级数据... */};
int fd = open("out.bin", O_WRONLY | O_CREAT, 0644);
write(fd, v.data(), v.size() * sizeof(float));
close(fd);struct 里有 std::string 或 vector 就不能直接 dump
一旦容器里存的是非 POD 类型(比如 std::vector<record></record>,而 Record 含 std::string),data() 拿到的只是对象的栈内存布局,里面 string 的指针指向堆,dump 出去再读就是野指针。
使用场景:日志结构体、网络包、配置快照——这些看似“简单”的 struct 很容易踩这个坑。
立即学习“C++免费学习笔记(深入)”;
- 错误示范:
struct LogEntry { int id; std::string msg; };→vec.data()dump 后,msg 字段完全不可恢复 - 替代方案只有序列化:手写
serialize()把 string.length() + data() 拆开写,或用flatbuffers/capnproto等 zero-copy 序列化库 - 如果只是临时进程间传递且双方 ABI 完全一致(同编译器、同 STL 版本、同对齐),可以强制 reinterpret_cast,但上线前务必做跨平台/跨编译器兼容性测试
大文件写入要处理 partial write 和 errno
write() 不保证一次写完全部字节,尤其在磁盘满、信号中断、NFS 挂载等场景下会返回 short write(写入字节数 errno 通常是 EINTR 或 ENOSPC,但不会报错退出。
性能影响:没处理 partial write,dump 文件就截断了,后续读取直接崩溃或解析错乱,而且问题难复现(只在特定负载下触发)。
- 必须循环调用
write(),直到所有字节写完,或遇到不可恢复错误(如ENOSPC、EFAULT) - 别只看返回值是否 -1,要看返回值是否小于预期长度
- 用
writev()替代多次write()可减少系统调用次数,但对单一块内存没优势
ssize_t to_write = total_bytes;
const char* ptr = static_cast<const char*>(v.data());
while (to_write > 0) {
ssize_t ret = write(fd, ptr, to_write);
if (ret == -1) {
if (errno == EINTR) continue;
else break; // real error
}
ptr += ret;
to_write -= ret;
}Windows 上用 _write() 要注意文本模式换行符干扰
在 Windows 默认 "wb" 模式下用 fwrite() 是安全的,但如果用 CRT 的 _write()(对应 POSIX write)且文件是以文本模式打开的(比如 fopen("x.bin", "w")),CR/LF 自动转换会破坏二进制内容。
兼容性影响:同一份代码在 Linux 编译运行正常,在 Windows 上 dump 出来文件大小变大、内容错位,debug 成本极高。
- Windows 下必须用
"wb"模式打开文件(fopen(..., "wb")),再用fileno()+_write();或者干脆全程用fwrite() - 避免混用:不要
fopen("wb")然后传给write()(fd 不合法),也不要CreateFile()后用fwrite()(FILE* 不匹配) - CMake 或构建脚本里记得加
-D_CRT_SECURE_NO_WARNINGS防止fopen被 warning 报警
真正麻烦的从来不是“怎么写进去”,而是“怎么确保下次一定能原样读出来”——类型对齐、端序、padding、ABI 稳定性,任何一个变化都会让 dump 文件变成废纸。线上服务 dump 前,至少用两个不同编译版本验证过读取逻辑。


















