使用nlohmann json存储含二维数组的结构体 替代易崩溃的boost序列化方案
实现方案
1. 基于nlohmann json的序列化方法
首先需要确保自定义类型Items已经实现了对应的json序列化/反序列化逻辑,再对MyStruct做如下适配:
#include <nlohmann/json.hpp> #include <fstream> #include <string> using json = nlohmann::json; // 先实现Items的json转换,以下为示例,根据Items的实际结构调整 struct Items { int id; std::string content; }; void to_json(json& j, const Items& item) { j = json{{"id", item.id}, {"content", item.content}}; } void from_json(const json& j, Items& item) { j.at("id").get_to(item.id); j.at("content").get_to(item.content); } // MyStruct的json转换实现 void to_json(json& j, const MyStruct& s) { // 二维数组转json嵌套数组 json item_arr = json::array(); for (int i = 0; i < 100; ++i) { json row = json::array(); for (int col = 0; col < 60; ++col) { row.push_back(s.item[i][col]); } item_arr.push_back(row); } j = json{ {"item", item_arr}, {"Something", s.Something}, {"X", s.X}, {"Y", s.Y} }; } void from_json(const json& j, MyStruct& s) { j.at("Something").get_to(s.Something); j.at("X").get_to(s.X); j.at("Y").get_to(s.Y); // 解析二维数组 auto& item_arr = j.at("item"); for (int i = 0; i < 100; ++i) { auto& row = item_arr.at(i); for (int col = 0; col < 60; ++col) { row.at(col).get_to(s.item[i][col]); } } } // 保存接口 void SaveJson(const std::string& name, const MyStruct& test) { std::ofstream out(name + ".json"); json j = test; out << j.dump(4); // 不需要格式化可直接调用dump() } // 读取接口 MyStruct ReadJson(const std::string& filename) { std::ifstream in(filename + ".json"); json j; in >> j; return j.get<MyStruct>(); }
json方案优势是可读性强、跨版本跨平台兼容性好,缺点是大体积数组序列化时性能和存储空间占用不如二进制方案。
2. 无Boost依赖的二进制序列化方案
你之前用Boost偶尔崩溃的核心原因大概率是没有指定二进制模式打开文件,Windows下文本模式会自动转换换行符,破坏二进制数据结构;另外Boost二进制存档本身存在跨版本不兼容的问题。
手动实现的二进制序列化方案如下,无任何第三方依赖,稳定性更高:
#include <fstream> #include <string> // 如果Items是非POD类型,参考std::string处理逻辑单独实现序列化/反序列化方法即可 void SaveBinary(const std::string& name, const MyStruct& test) { std::ofstream out(name + ".dat", std::ios::binary); // 序列化基础类型字段 out.write(reinterpret_cast<const char*>(&test.X), sizeof(test.X)); out.write(reinterpret_cast<const char*>(&test.Y), sizeof(test.Y)); // 序列化字符串:先存长度再存内容 size_t str_len = test.Something.size(); out.write(reinterpret_cast<const char*>(&str_len), sizeof(str_len)); out.write(test.Something.data(), str_len); // 序列化固定大小二维数组,Items为POD类型可直接批量写入 out.write(reinterpret_cast<const char*>(&test.item), sizeof(test.item)); out.close(); } MyStruct ReadBinary(const std::string& filename) { MyStruct test{}; std::ifstream in(filename + ".dat", std::ios::binary); // 读取基础字段 in.read(reinterpret_cast<char*>(&test.X), sizeof(test.X)); in.read(reinterpret_cast<char*>(&test.Y), sizeof(test.Y)); // 读取字符串 size_t str_len = 0; in.read(reinterpret_cast<char*>(&str_len), sizeof(str_len)); test.Something.resize(str_len); in.read(test.Something.data(), str_len); // 读取二维数组 in.read(reinterpret_cast<char*>(&test.item), sizeof(test.item)); in.close(); return test; }
如果需要跨平台使用,仅需额外处理大小端转换、固定字段字节长度即可,兼容性完全可控。
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

