1. 引言
序列化(Serialization)是指将程序中的内存对象(如结构体、类实例、列表等)转换成一种可以存储或传输的格式(通常是字节流或文本)的过程。常见的序列化格式包括:
- JSON(文本,人类可读)
- XML
- Protocol Buffers(二进制,高效)
- MessagePack
- YAML
- 甚至自定义的二进制格式
反序列化(Deserialization)是序列化的逆过程:将序列化后的数据(如 JSON 字符串)重新转换回程序中的内存对象。
2. 原因
那么,为什么需要序列化和反序列化呢?笔者的体会是不序列化/反序列化也行,只不过在进行相应的读取和写入操作的时候会非常繁琐。比如一个配置文件更新:
假设我们有一个博客系统的配置,包含站点标题、作者名、是否启用评论、默认封面地址等多个字段。如果不使用序列化机制,每次读取配置时,就得手动打开 JSON(或 YAML、INI)文件,逐行解析,判断每个字段是否存在、类型是否正确,再一一赋值给程序中的变量;而当用户修改了某个设置、需要保存回文件时,又得手动拼接字符串、处理引号转义、数组格式、缩进对齐……稍有不慎,就会生成格式错误的文件,导致程序下次启动失败。
更麻烦的是,一旦配置结构发生变化——比如新增一个 theme 字段,或者把 enableComments 拆成 enablePostComments 和 enablePageComments——我们就不得不同时修改读取逻辑、写入逻辑、默认值初始化、错误处理等多处代码,极易遗漏或出错。
而有了序列化和反序列化,这一切就变得简洁而可靠:定义好结构体(或类),注册对应的转换函数,一行代码就能从 JSON 构造出完整的配置对象,另一行代码就能把修改后的对象写回文件。字段增减只需调整结构体,读写逻辑几乎无需改动,既减少了重复劳动,也大大提升了健壮性和可维护性。
因此,序列化/反序列化并非“必须”,但它是对抗复杂性、提升开发效率和系统可靠性的重要工具。
3. 实现
3.1 示例
这里就举例实现一下 C++ 中 JSON 序列化和反序列化。如果要反序列化成 C++ 可以使用的内存对象,最好的数据容器就是 struct 。当然 class 也可以,不过我们都知道 struct 和 class 的区别:struct 的成员一般默认是公有的,而 class 的成员一般默认是私有的。因此,struct 适合以数据成员为主的,比较简单的对象;class 适合以方法成员为主的,比较复杂的对象。
笔者使用 nlohmann/json 中序列化/反序列化一个表达博客的数据对象:
BlogMeta.h:- #include <nlohmann/json.hpp>
- #include <string>
- #include <vector>
- #include "PostStats.h"
- namespace DataTransfer {
- /// @brief 一篇博客的元数据
- struct BlogMeta {
- std::string id;
- std::string title;
- std::string summary;
- std::string createdTime;
- std::string updatedTime;
- std::string coverAddress;
- int64_t isDraft;
- std::vector<std::string> tagNames;
- std::vector<std::string> categoryNames;
- PostStats postStats;
- // 提供序列化接口
- friend void to_json(nlohmann::json& j, const BlogMeta& s);
- // 提供反序列化接口
- friend void from_json(const nlohmann::json& j, BlogMeta& s);
- };
复制代码 BlogMeta.cpp:- #include "BlogMeta.h"
- #include "Util/GetTime.h"
- namespace DataTransfer {
- // 提供序列化接口
- void to_json(nlohmann::json& j, const BlogMeta& s) {
- j = nlohmann::json{{"id", s.id},
- {"title", s.title},
- {"summary", s.summary},
- {"createdTime", s.createdTime},
- {"updatedTime", s.updatedTime},
- {"coverAddress", s.coverAddress},
- {"isDraft", s.isDraft},
- {"tagNames", s.tagNames},
- {"categoryNames", s.categoryNames},
- {"postStats", s.postStats}};
- }
- // 提供反序列化接口
- void from_json(const nlohmann::json& j, BlogMeta& s) {
- s.id = j.at("id").get<std::string>();
- s.title = j.at("title").get<std::string>();
- s.summary = j.at("summary").get<std::string>();
- s.createdTime = j.at("createdTime").get<std::string>();
- s.updatedTime =
- j.value("updatedTime", Util::GetCurrentTime()); //提供默认值,增加稳定性
- s.coverAddress = j.at("coverAddress").get<std::string>();
- s.isDraft = j.at("isDraft").get<int64_t>();
- s.tagNames = j.at("tagNames").get<std::vector<std::string>>();
- s.categoryNames = j.at("categoryNames").get<std::vector<std::string>>();
- s.postStats = j.at("postStats").get<PostStats>();
- }
- } // namespace DataTransfer
复制代码 其中 to_json / from_json 就是对应的 序列化 / 反序列化接口。只需要填充这一对接口,就可以通过赋值运算符=实现自动序列化和反序列化:
[code]#include #include #include "BlogMeta.h" // 包含你的 BlogMeta 定义int main() { using namespace DataTransfer; using json = nlohmann::json; // ---------------------------- // 1. 创建一个 BlogMeta 对象(内存中的数据) // ---------------------------- BlogMeta blog; blog.id = "blog-001"; blog.title = "深入理解 C++ 序列化"; blog.summary = "本文介绍如何使用 nlohmann/json 进行安全高效的序列化。"; blog.createdTime = "2025-12-22T10:00:00Z"; blog.updatedTime = "2025-12-22T17:00:00Z"; // 可省略,反序列化时会用默认值 blog.coverAddress = "/images/cpp_serialization.jpg"; blog.isDraft = 0; blog.tagNames = {"C++", "JSON", "Serialization"}; blog.categoryNames = {" rogramming", "Tutorial"}; blog.postStats = {1200, 85, 23}; // ---------------------------- // 2. 序列化:BlogMeta → JSON // ---------------------------- json j = blog; // 自动调用 to_json std::cout |