Protobuf 是Google官方出品一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说是序列化。它很适合做数据存储或RPC数据交换格式。可用于通讯协议、数据存储等领域的平台无关、语言无关、可扩展的序列化结构数据格式。
优点
-
平台无关,语言无关,可扩展
-
提供了友好的动态库,使用简单
-
解析速度快,比对应的XML快约20-100倍
-
序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10
缺点
protobuf对于1M以下的message有很高的效率,但是当message是大于1M的大块数据时,protobuf的表现不是很好,请合理使用。
Proto文件
使用 protobuf, 需要先书写 .proto 文件,然后编译该文件。编译 proto 文件则需要使用官方的 protoc 工具。
// Filename: addressbook.proto syntax="proto2"; // 表明使用protobuf的编译器版本为v2,目前最新的版本为v3 package addressbook; message Person { //message是Protobuf中的结构化数据,类似于C++中的类,可以在其中定义需要处理的数据 required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } message AddressBook { repeated Person person_info = 1; } /* 1,2,3 是字段的标识号,在消息定义中,每个字段都有唯一的一个数字标识号,这些标识号是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。 标识号的范围在:1 ~ 229 - 1,其中[19000-19999]为Protobuf预留,不能使用。 Person 内部声明了一个enum和一个message,这类似于C++中的类内声明,Person外部的结构可以用 Person.PhoneType 的方式来使用PhoneType。当使用外部package中的结构时,要使用 pkgName.msgName.typeName 的格式,每两层之间使用'.'来连接,类似C++中的"::"。 */
标量类型列表
proto类型 | C++类型 | 备注 |
double | double | |
float | float | |
int32 | int32 | 使用可变长编码,编码负数时不够高效——如果字段可能含有负数,请使用sint32 |
int64 | int64 | 使用可变长编码,编码负数时不够高效——如果字段可能含有负数,请使用sint64 |
uint32 | uint32 | 使用可变长编码 |
uint64 | uint64 | 使用可变长编码 |
sint32 | int32 | 使用可变长编码,有符号的整型值,编码时比通常的int32高效 |
sint64 | int64 | 使用可变长编码,有符号的整型值,编码时比通常的int64高效 |
fixed32 | uint32 | 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效 |
fixed64 | uint64 | 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效 |
sfixed32 | int32 | 总是4个字节 |
sfixed64 | int64 | 总是8个字节 |
bool | bool | |
string | string | 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本 |
bytes | string | 可能包含任意顺序的字节数据 |
win10系统下,C++开发如何使用
1、源码安装
访问最新地址,c++ 开发则下载 protobuf-cpp-3.19.1.tar.gz
; 或是 protoc-3.19.1-win64.zip
https//github.com/protocolbuffers/protobuf/release/latest
2、解压源码到任意路径下
path/protobuf-3.19.1
3、下载 CMake 工具
4、CMake生成 VS2019 工程
-
打开CMake
-
设置源码路径下的cmake目录
path/protobuf-3.19.1/cmake
-
设置任意构建目录
path/protobuf_build
-
点击 configure、选择对应 VS,编译为 WINI32,编译器默认
-
点击Finish按钮,开始自动编译
-
点击 Generate 生成VS项目
-
用 VS 打开生成的工程,按需要选择编译 libprotobuf、libprotobuf-lite、libprotoc和protoc项目
-
在 release 或者 debug目录,找到 lib 文件和 protoc.exe
5、protoc.exe 使用命令行将 .proto 文件编译生成对应的 .h 和 .cc 文件
# 标准命令 protoc -I=./ --cpp_out=./ ./test.proto #--cpp_out 是输出路径, ./为当前路径
6、引入自己的 VS2019 工程使用
-
拷贝 *.pb.cc 和 *.pb.h 文件到当前项目
-
拷贝 src目录下的goole文件夹到当前项目的include目录下
-
拷贝 libprotobuf.lib libprotoc.lib 到当前项目的 lib 目录下
-
项目设置为多字节,添加静态链接库
-
C/C++ General Additional Include Directories 添加include目录
-
Linker General Additional Library Directories 添加 lib 目录
-
Linker Input Additional Dependencies 添加 lib 字段名
7、VS编译或是g++编译生成可执行代码
g++ main.cc xxx.pb.cc -I $INCLUDE_PATH -L $LIB_PATH -lprotobuf -pthread
常用API
protoc 为message的每个required字段和optional字段都定义了一下几个函数,不限于这几个
TypeName xxx() const; //获取字段 // bool has_xxx(); //判断是否设置值 pb 2 void set_xxx(const TypeName&); //设置 void clear_xxx(); //使其变为默认值
为每个 repeated 字段定义了以下几个:
TypeName* add_xxx(); //增加结点 TypeName xxx(int) const; //获取指定序号的结点,类似于c++的“[]”运算符 TypeName* mutable_xxx(int); //类似于上一个,但是获取的是指针 int xxx_size(); //获取结点的数量
几个常用的序列化函数
bool SerializeToOstream(std::ostream * output) const; //输出到输出流中 bool SerializeToString(string * output) const; //输出到string bool SerializeToArray(void * data, int size) const; //输出到字节流
与之对应的反序列化函数
bool ParseFromIstream(std::istream * input); //从输入流解析 bool ParseFromString(const string & data); //从string解析 bool ParseFromArray(const void * data, int size); //从字节流解析
其他常用函数
bool IsInitialized(); // 检查是否所有required字段都被设值 size_t ByteSize() const; // 获取二进制字节序的大小 pb2
官方API文档: https://developers.google.com/protocol-buffers/docs/reference/overview
参考资料
https://www.cnblogs.com/autyinjing/p/6495103.html