商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > c++序列化对象到文件方法 c++如何将class对象存入文件

c++序列化对象到文件方法 c++如何将class对象存入文件

  发布于2026-07-18 阅读(0)

扫一扫,手机访问

C++ 对象持久化,这事儿说难不难,说简单也不简单。很多开发者第一次遇到“把 class 存到文件”的需求时,往往先想到的是直接写二进制流——这确实是最直接的方式,但里面的坑,一个比一个深。

先看最直接的做法:用 std::ofstream 二进制写入。如果你的类没有指针、虚函数、动态分配内存,所有成员都是基本类型或 std::array 这样的固定大小容器,那逐字段写入确实没问题。比如一个简单的 Person 结构体:

class Person {
public:
    int id;
    char name[32];
    double salary;
};

// 写入
std::ofstream file("person.bin", std::ios::binary);
Person p{101, "Alice", 8500.0};
file.write(reinterpret_cast(&p), sizeof(p));
file.close();

看着挺干净,但有几个细节必须注意:sizeof(p) 包含结构体填充字节,不同编译器、不同平台的对齐方式可能不一样,这就意味着跨平台读取时可能出问题。另外,char name[32] 是安全的,因为它在栈上固定分配。但如果是 std::string,这么写就完蛋了——它内部存的是指针,直接写进去只保存了地址值,等下次读取时,那个地址指向的内容早就没了,程序崩得妥妥的。

std::string 和 std::vector 必须显式序列化长度+数据

标准容器不是 POD 类型,内存布局不连续,所以不能直接写。正确的做法是:先写长度,再写内容。比如:

class Data {
public:
    std::string msg;
    std::vector nums;
};

void sa ve(const Data& d, std::ofstream& out) {
    size_t len = d.msg.size();
    out.write(reinterpret_cast(&len), sizeof(len));
    out.write(d.msg.data(), len); // 不带 '\0'

    len = d.nums.size();
    out.write(reinterpret_cast(&len), sizeof(len));
    if (!d.nums.empty()) {
        out.write(reinterpret_cast(d.nums.data()), len * sizeof(int));
    }
}
  • 字符串不写结尾 \0,读取时按长度申请空间再读
  • std::vectordata() 可能为 nullptr,要判空避免 write(nullptr, 0) 行为未定义
  • 跨平台时注意 size_t 大小(32/64 位不一致),建议统一用 uint64_t

手动操作虽然可控,但代码量不小,而且容易遗漏字段。如果觉得这么搞太麻烦,可以考虑 Boost 的方案。

用 boost::serialization 省事但需链接 Boost,且类要可默认构造

Boost 提供反射式序列化,支持指针、继承、STL 容器,但要求类有默认构造函数(反序列化时先构造再赋值)。用起来是这样的:

#include 
#include 

class Config {
public:
    std::string host;
    int port;
    Config() = default; // 必须存在
private:
    friend class boost::serialization::access;
    template
    void serialize(Archive& ar, const unsigned int) {
        ar & host & port;
    }
};

// 写入
std::ofstream ofs("config.bin", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << config;
  • 头文件引入即可,无需手动处理内存布局
  • 不支持 const 成员、引用成员;私有成员需设为 friend
  • 二进制归档格式不跨版本兼容(Boost 1.75 写的文件,1.80 不一定读得动)

有意思的是,Boost 虽然方便,但它的二进制归档格式在版本之间并不稳定。如果你需要长期存储数据,或者跨语言交互,这条路并不稳。

生产环境推荐 protobuf 或 msgpack:跨语言、向后兼容、体积小

话说回来,如果对象要存好几年,或者需要跟 Python、Go 等其他语言交互,手写或者 Boost 都不够稳健。这时候,Protocol Buffers 或 msgpack 才是正解。拿 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);

std::ofstream out("person.pb", std::ios::binary);
p.SerializeToOstream(&out); // 自动处理变长整数、字符串长度、嵌套等
  • 字段可选、可新增,旧程序读新数据会忽略未知字段
  • 序列化结果比纯二进制还小(varint 编码、无填充)
  • 没有运行时反射开销,比 Boost 快,也比手写更难出错

其实,真正麻烦的从来不是“怎么写进去”,而是“以后还能不能读出来”。字段改名、加默认值、换编译器、升级标准库,都可能让昨天还能读的文件今天直接罢工。所以,选方案之前,先想清楚这个对象要存多久、谁会来读它——这才是关键所在。

本文转载于:https://www.php.cn/faq/2341044.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注