如何序列化与反序列化C++11中的std::vector<details>结构体向量?
嘿,作为刚接触C序列化的初学者,我太懂你现在的困惑了——把内存里的std::vector<details>存到文件或者传去别的地方,再完整读回来还原,确实需要清晰易懂的步骤。下面我给你讲两种适合C11的方法,都是新手友好型的:
方法一:手动实现序列化/反序列化(无第三方库)
这种方法能让你彻底搞懂序列化的本质:就是把结构体的每个成员按固定格式写入流,再按一模一样的格式读出来还原。非常适合新手理解原理。
首先先假设你的details结构体是这样的(如果你的结构体成员不同,只要对应修改读写逻辑就行):
#include <vector> #include <fstream> #include <string> #include <stdexcept> #include <iostream> // 你的details结构体示例 struct details { int id; std::string name; double value; };
序列化函数:把向量写入文件
// 序列化:将vector<details>写入二进制文件 void serialize(const std::vector<details>& vec, const std::string& filename) { // 一定要用二进制模式打开文件,避免文本模式自动转换换行符导致数据错乱 std::ofstream file(filename, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("无法打开文件进行序列化"); } // 先写入向量的元素个数,这样反序列化时知道要读多少个元素 const size_t vec_size = vec.size(); file.write(reinterpret_cast<const char*>(&vec_size), sizeof(vec_size)); // 逐个写入每个details的成员 for (const auto& item : vec) { // 写入int类型的id file.write(reinterpret_cast<const char*>(&item.id), sizeof(item.id)); // 写入std::string:必须先写字符串长度,再写内容(直接写string对象会存内部指针,反序列化会失效) const size_t name_len = item.name.size(); file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len)); file.write(item.name.data(), name_len); // 写入double类型的value file.write(reinterpret_cast<const char*>(&item.value), sizeof(item.value)); } }
反序列化函数:从文件还原向量
// 反序列化:从二进制文件读取并还原vector<details> std::vector<details> deserialize(const std::string& filename) { std::ifstream file(filename, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("无法打开文件进行反序列化"); } std::vector<details> result; // 先读取向量的元素个数 size_t vec_size; file.read(reinterpret_cast<char*>(&vec_size), sizeof(vec_size)); result.reserve(vec_size); // 提前分配空间,提升效率 // 逐个读取并还原每个details对象 for (size_t i = 0; i < vec_size; ++i) { details item; // 读取id file.read(reinterpret_cast<char*>(&item.id), sizeof(item.id)); // 读取string:先读长度,再分配空间读取内容 size_t name_len; file.read(reinterpret_cast<char*>(&name_len), sizeof(name_len)); item.name.resize(name_len); file.read(&item.name[0], name_len); // 读取value file.read(reinterpret_cast<char*>(&item.value), sizeof(item.value)); result.push_back(item); } return result; }
测试用例
int main() { // 构造测试数据 std::vector<details> object_details = { {1, "张三", 3.1415}, {2, "李四", 2.7182}, {3, "王五", 1.4142} }; // 序列化到文件 try { serialize(object_details, "details_data.dat"); std::cout << "序列化成功!已保存到details_data.dat" << std::endl; } catch (const std::exception& e) { std::cerr << "序列化失败:" << e.what() << std::endl; return 1; } // 反序列化还原数据 std::vector<details> restored_data; try { restored_data = deserialize("details_data.dat"); std::cout << "\n反序列化成功!还原的数据如下:" << std::endl; for (const auto& item : restored_data) { std::cout << "ID: " << item.id << ", 名称: " << item.name << ", 值: " << item.value << std::endl; } } catch (const std::exception& e) { std::cerr << "反序列化失败:" << e.what() << std::endl; return 1; } return 0; }
手动实现的注意事项
- 必须用二进制模式打开文件,否则文本模式会自动转换
\n等换行符,导致数据错位。 - 对于
std::string、std::vector这类动态容器,不能直接写入整个对象(因为它们内部存的是指针),必须先写长度再写内容。 - 如果你的
details有嵌套结构体、指针等复杂成员,需要扩展对应的读写逻辑。
方法二:使用Boost.Serialization(更适合复杂场景)
如果你的项目允许使用第三方库,Boost.Serialization是C生态里非常成熟的序列化工具,完美支持C11。它能自动处理几乎所有标准库类型(包括std::vector、std::string),不用手动写每个成员的读写逻辑,适合结构体复杂的实际项目。
步骤1:准备Boost库
你需要安装Boost库(C++11对应的Boost版本建议选1.58及以上),确保编译环境能找到Boost的头文件和库文件。
代码实现
#include <vector> #include <fstream> #include <string> #include <iostream> #include <boost/archive/binary_oarchive.hpp> #include <boost/archive/binary_iarchive.hpp> #include <boost/serialization/vector.hpp> #include <boost/serialization/string.hpp> struct details { int id; std::string name; double value; // 必须添加这个模板化的serialize函数,Boost会通过它访问结构体成员 template<class Archive> void serialize(Archive& ar, const unsigned int /*version*/) { ar & id; // 序列化id ar & name; // 序列化name(Boost自动处理string) ar & value; // 序列化value } }; // 序列化函数 void serialize_with_boost(const std::vector<details>& vec, const std::string& filename) { std::ofstream file(filename, std::ios::binary); boost::archive::binary_oarchive oa(file); oa << vec; // 直接序列化整个vector,Boost自动处理内部的details对象 } // 反序列化函数 std::vector<details> deserialize_with_boost(const std::string& filename) { std::vector<details> result; std::ifstream file(filename, std::ios::binary); boost::archive::binary_iarchive ia(file); ia >> result; // 直接反序列化还原vector return result; } // 测试用例和方法一类似,替换成这两个函数即可 int main() { std::vector<details> object_details = { {1, "张三", 3.1415}, {2, "李四", 2.7182}, {3, "王五", 1.4142} }; try { serialize_with_boost(object_details, "boost_details.dat"); std::cout << "Boost序列化成功!" << std::endl; auto restored_data = deserialize_with_boost("boost_details.dat"); std::cout << "\nBoost反序列化成功!还原的数据:" << std::endl; for (const auto& item : restored_data) { std::cout << "ID: " << item.id << ", 名称: " << item.name << ", 值: " << item.value << std::endl; } } catch (const std::exception& e) { std::cerr << "出错了:" << e.what() << std::endl; return 1; } return 0; }
Boost方法的注意事项
- 编译时需要链接Boost的serialization库,比如在GCC下编译要加参数:
g++ your_code.cpp -o your_program -lboost_serialization。 - 如果你的
details有父类或者嵌套结构体,只需要给每个类都添加serialize函数即可。 - Boost还支持文本格式、XML格式的序列化,只要替换对应的归档类(比如
text_oarchive)就行。
总结
- 如果你是新手想彻底搞懂序列化原理,先从手动实现开始,能清楚看到数据的读写过程。
- 如果是实际项目开发,尤其是结构体复杂的情况,Boost.Serialization更高效,能减少手动写代码的出错概率。
内容的提问来源于stack exchange,提问作者2adnielsenx xx
相关产品推荐
相关产品推荐

