直接用 std::ofstream 二进制写入仅适用于无指针、无虚函数、无动态内存的 POD 类型;std::string 和 std::vector 需显式序列化长度与数据;跨平台应统一用 uint64_t 替代 size_t;Boost::serialization 简便但需默认构造且不跨版本兼容;生产环境推荐 Protocol Buffers 或 msgpack,保障跨语言、向后兼容与长期可读性。

用 std::ofstream 手动写入成员变量最直接,但仅适用于简单 POD 类型
如果你的 class 没有指针、虚函数、动态分配内存,且所有成员都是基本类型或标准容器(如 std::array),可以逐字段写入二进制文件:
class Person {
public:
int id;
char name[32];
double salary;
};
<p>// 写入
std::ofstream file("person.bin", std::ios::binary);
Person p{101, "Alice", 8500.0};
file.write(reinterpret_cast<const char>(&p), sizeof(p));
file.close();
</const></p>
注意:sizeof(p) 包含结构体填充字节,不同编译器/平台可能对齐不同;char name[32] 是安全的,但 std::string 不能这么写——它内部是指针,直接写只会保存地址值,读取时必然崩溃。
std::string 和 std::vector 必须显式序列化长度+数据
标准容器不是 POD,其内存布局不连续。必须先写长度,再写内容:
class Data {
public:
std::string msg;
std::vector<int> nums;
};
<p>void save(const Data& d, std::ofstream& out) {
size_t len = d.msg.size();
out.write(reinterpret_cast<const char>(&len), sizeof(len));
out.write(d.msg.data(), len); // 不带 '\0'</const></p>
<pre class="brush:php;toolbar:false;">len = d.nums.size();
out.write(reinterpret_cast<const char>(&len), sizeof(len));
if (!d.nums.empty()) {
out.write(reinterpret_cast<const char>(d.nums.data()), len * sizeof(int));
}</const></const>
}
- 字符串不写结尾
\0,读取时按长度申请空间再读 - 空
std::vector的data()可能为nullptr,要判空避免write(nullptr, 0)行为未定义 - 跨平台时注意
size_t大小(32/64 位不一致),建议统一用uint64_t
用 boost::serialization 省事但需链接 Boost,且类要可默认构造
Boost 提供反射式序列化,支持指针、继承、STL 容器,但要求类有默认构造函数(反序列化时先构造再赋值):
#include <boost>
#include <boost><p>class Config {
public:
std::string host;
int port;
Config() = default; // 必须存在
private:
friend class boost::serialization::access;
template<class archive>
void serialize(Archive& ar, const unsigned int) {
ar & host & port;
}
};</class></p>
<p>// 写入
std::ofstream ofs("config.bin", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa </p></boost></boost>
- 头文件引入即可,无需手动处理内存布局
- 不支持
const成员、引用成员;私有成员需设为friend - 二进制归档格式不跨版本兼容(Boost 1.75 写的文件,1.80 不一定读得动)
生产环境推荐 protobuf 或 msgpack:跨语言、向后兼容、体积小
如果对象要长期存储、或与其他语言(Python/Go)交互,手写或 Boost 都不够稳健。Protobuf 需先定义 .proto 文件:
syntax = "proto3";
message Person {
int32 id = 1;
string name = 2;
double salary = 3;
}
生成 C++ 类后,序列化只需两行:
Person p;
p.set_id(101);
p.set_name("Alice");
p.set_salary(8500.0);
<p>std::ofstream out("person.pb", std::ios::binary);
p.SerializeToOstream(&out); // 自动处理变长整数、字符串长度、嵌套等
</p>
- 字段可选、可新增,旧程序读新数据会忽略未知字段
- 序列化结果比纯二进制还小(varint 编码、无填充)
- 没有运行时反射开销,比 Boost 快,也比手写更难出错
真正麻烦的从来不是“怎么写进去”,而是“以后还能不能读出来”——字段改名、加默认值、换编译器、升级标准库,都可能让昨天能读的文件今天直接失败。选方案前,先想清楚这个对象要存多久、谁会来读它。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











