ProtoBuf在中C++使用介绍
ProtoBuf的定义和描述:
- Protocol Buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
- Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
- 你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
使用 ProtoBuf教程:
对 ProtoBuf 的基本概念有了一定了解之后,我们来看看具体该如何使用 ProtoBuf。
第一步,创建 .proto 文件,定义数据结构,如下所示:
//person.proto
package test;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
我们在上例中定义了一个名为 Person的消息,语法很简单,message 关键字后跟上消息名称。之后我们在其中定义了 message 具有的字段,形式为:
message xxx {
// 字段规则:required -> 字段只能也必须出现 1 次
// 字段规则:optional -> 字段可出现 0 次或1次
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
字段规则 类型 名称 = 字段编号;
}
第二步,protoc 编译 .proto 文件生成读写接口:
在.proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输。当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。ProtoBuf 提供相应的接口代码,可以通过 protoc 这个编译器来生成相应的接口代码,命令如下:
// $SRC_DIR: .proto 所在的源目录
// --cpp_out: 生成 c++ 代码
// $DST_DIR: 生成代码的目标目录
// xxx.proto: 要针对哪个 proto 文件生成接口代码
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
protoc ./person.proto --cpp_out=./
生成的.h,.cpp文件为person.pb.h,person.pb.cpp,且.h的定义与proto文件的内容相关联:
namespace test { // 对应 package test;
class Person : public ::google::protobuf::Message { //对应 message Person 且继承自::google::protobuf::Message
public:
inline void set_name(const ::std::string& value); //对应message的字段内容
inline void set_email(const ::std::string& value);
inline void set_id(::google::protobuf::int32 value);
...
}
第三步,编写C++业务代码:
#include <iostream>
#include <fstream>
#include "person.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"
using namespace test;
int main(){
Person p;
p.set_name("test");
p.set_id(100);
p.set_email("a.iabc.com");
//------------------将pb二进制信息保存到字符串
std::string str;
p.SerializeToString(&str);
std::cout<<"str: ["<<str<<"]"<<std::endl;
//------------------将pb文本信息写入文件
std::ofstream fw;
fw.open("./Person.txt", std::ios::out | std::ios::binary);
google::protobuf::io::OstreamOutputStream *output = new google::protobuf::io::OstreamOutputStream(&fw);
google::protobuf::TextFormat::Print(p, output);
delete output;
fw.close();
//---------------------将pb文本信息保存到字符串
std::string str1;
google::protobuf::TextFormat::PrintToString(p, &str1);
std::cout<<"str1: ["<<str1<<"]"<<std::endl;
//---------------------反序列化
Person p1;
p1.ParseFromString(str);
std::cout<<"name:"<<p1.name()<<",email:"<<p1.email()<<",id:"<<p1.id()<<std::endl;
return 0;
}
运行结果:
[root@192 protobuf_test]# g++ -g -o test_person test_person.cpp ./person.pb.cc -I. -lprotobuf -pthread -std=c++11
[root@192 protobuf_test]# ./test_person
str: [
testd
a.iabc.com]
str1: [name: "test"
id: 100
email: "a.iabc.com"
]
name:test,email:a.iabc.com,id:100
[root@192 protobuf_test]#
api说明:
- p.SerializeToString(&str):将对象p序列化成二进制数据,保存到字符串中;
- 二进制虽然小,但是可读性差,所以通过google::protobuf::TextFormat::print()方法生成文本数据写入文件;为此需要引入google/protobuf/text_format.h(否则会报‘google::protobuf::TextFormat’ has not been declared错误)、zero_copy_stream_impl.h(否则会报OstreamOutputStream找不到)
- 除了将pb信息序列化成文本写入文件外,还可以调用google::protobuf::TextFormat::PrintToString(mrlist, &str1); 方法将pb文本信息保存到字符串中;(别忘了加text_format.h头文件)
- p1.ParseFromString(str);:将字符串中的二进制信息反序列成Person对象;
- C++版pb的api一般为:pb对象.set_消息属性(value);设置属性值;pb对象.消息属性();获取属性值。
参考: