Protocol Buffer Serialization 指的是使用 Protocol Buffer 进行数据序列化的过程。在这个过程中,结构化的数据被转换成 Protocol Buffer 的二进制格式、以便于存储、传输或者在不同的系统之间进行交换。
Protocol Buffer Serialization 的优点包括序列化后数据的紧凑性、高效性以及跨语言、跨平台的兼容性。这使得它成为许多分布式系统和网络通信中的首选序列化方法之一。
1. Proto 编译
syntax = "proto3"; enum Week { Mon = 0; Tue = 1; Wed = 2; Thu = 3; Fri = 4; Sat = 5; Sun = 6; } message Custom { int32 attr1 = 1; int32 attr2 = 2; } message Demo { // 字段存储中文,使用 bytes 类型替换 string 类型 bytes name = 1; int32 numb = 2; Week week = 3; repeated int32 rept = 4; map<string, int32> mpsi = 5; Custom cust = 6; }
当编写完数据定义相关的 .proto 文件,我们还需要使用 protobuf 编译器来生成对应语言的数据类文件。
对于 C++,每个 proto 文件会生成两种不同的文件:
- foo_pb.h:头文件
- foo_pb.cc:实现文件
protoc *.proto --cpp_out=.
2. 对象序列化
#include <iostream> #include <fstream> using namespace std; #include "demo.pb.h" void test01() { Demo demo; // 1. 基本字段 demo.set_name("张三"); demo.set_numb(18); demo.set_week(Week::Sat); cout << demo.name() << " " << demo.numb() << " " << demo.week() << endl; // 2. repeated 字段 // 添加 demo.add_rept(100); demo.add_rept(200); demo.add_rept(300); // 修改 demo.set_rept(1, 666); // 删除 demo.mutable_rept()->erase(demo.rept().begin()); // 访问 for (auto it = demo.rept().begin(); it != demo.rept().end(); ++it) cout << *it << " "; cout << endl; cout << demo.rept()[0] << endl; // 3. map 字段 // 插入 demo.mutable_mpsi()->insert({ "aaa", 100 }); demo.mutable_mpsi()->insert({ "bbb", 200 }); demo.mutable_mpsi()->insert(pair<string, int>("ccc", 300)); cout << (int)demo.mutable_mpsi()->size() << endl; // 修改 (*demo.mutable_mpsi())["ccc"] = 888; // 删除 demo.mutable_mpsi()->erase("aaa"); // 查询 auto pos = demo.mpsi().find("bbb"); cout << pos->first << " " << pos->second << endl; // 遍历 for (auto it = demo.mpsi().begin(); it != demo.mpsi().end(); ++it) cout << it->first << " " << it->second << endl; // 4. 自定义类型 demo.mutable_cust()->set_attr1(123); demo.mutable_cust()->set_attr2(456); cout << demo.cust().attr1() << " " << demo.cust().attr2() << endl; } void test02() { // 构造函对象 Demo demo; demo.set_name("张三"); demo.set_numb(100); demo.add_rept(10); demo.add_rept(20); demo.set_week(Week::Thu); demo.mutable_mpsi()->insert({"aaa", 111}); demo.mutable_mpsi()->insert({"bbb", 222}); demo.mutable_cust()->set_attr1(123); demo.mutable_cust()->set_attr2(456); // 1. 序列化到数组 size_t object_size = demo.ByteSizeLong(); char* data2 = new char[object_size]; demo.SerializeToArray(data2, (int)object_size); ofstream("data2.bin", ios::binary).write(data2, object_size); // 2. 序列化到字符串 string data1 = demo.SerializeAsString(); ofstream("data1.bin", ios::binary).write(data1.data(), data1.size()); // 3. 序列化到输出流 ofstream ofs3("data3.bin", ios::binary); demo.SerializeToOstream(&ofs3); } void print_demo(Demo& demo) { cout << "name:" << demo.name() << endl; cout << "numb:" << demo.numb() << endl; cout << "week:" << demo.week() << endl; cout << "rept:"; for (auto it = demo.rept().begin(); it != demo.rept().end(); ++it) cout << *it << " "; cout << endl; cout << "mpsi:"; for (auto it = demo.mpsi().begin(); it != demo.mpsi().begin(); ++it) cout << it->first << " " << it->second << endl; cout << "cust:" << demo.cust().attr1() << " " << demo.cust().attr2() << endl; } // 3. 反序列化 void test03() { Demo demo; // ifstream ifs("data1.bin", ios::in | ios::binary); // ifstream ifs("data2.bin", ios::in | ios::binary); ifstream ifs("data3.bin", ios::binary); demo.ParseFromIstream(&ifs); print_demo(demo); } int main() { test01(); test02(); test03(); return 0; }