Protobuf

protobuf是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。

为什么要用?
  - 平台无关,语言无关,可扩展;
  - 提供了友好的动态库,使用简单;
  - 解析速度快,比对应的XML快约20-100倍;
  - 序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。

 

1.初始化环境:

源码下载地址: https://github.com/google/protobuf

安装依赖的库: autoconf automake libtool curl make g++ unzip 不知道什么作用但是mac下没有安装也能行

安装:

$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install

2.编写pro.proto文件

syntax="proto2";

package addressbook;

//import "src/help.proto"; //举例用,编译时去掉

message Person {

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;

}

注意:

syntax="proto2";放首行

syntax="proto2"; 表明使用protobuf的编译器版本为v2,目前最新的版本为v3

package addressbook; 声明了一个包名,用来防止不同的消息类型命名冲突,类似于 namespace

import "src/help.proto";  导入了一个外部proto文件中的定义,类似于C++中的 include 。

 message 是Protobuf中的结构化数据,类似于C++中的类,可以在其中定义需要处理的数据

required string name = 1; 声明了一个名为name,数据类型为string的required字段,字段的标识号为1  
protobuf一共有三个字段修饰符:  
  - required:该值是必须要设置的;  
  - optional :该字段可以有0个或1个值(不超过1个);  
  - repeated:该字段可以重复任意多次(包括0次),类似于C++中的list;

使用建议:除非确定某个字段一定会被设值,否则使用optional代替required。

string 是一种标量类型,protobuf的所有标量类型请参考文末的标量类型列表。

name 是字段名,1 是字段的标识号,在消息定义中,每个字段都有唯一的一个数字标识号,这些标识号是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。

标识号的范围在:1 ~ 229 - 1,其中[19000-19999]为Protobuf预留,不能使用。

Person 内部声明了一个enum和一个message,这类似于C++中的类内声明,Person外部的结构可以用 Person.PhoneType 的方式来使用PhoneType。当使用外部package中的结构时,要使用 pkgName.msgName.typeName 的格式,每两层之间使用'.'来连接,类似C++中的"::"。  
 optional PhoneType type = 2 [default = HOME]; 为type字段指定了一个默认值,当没有为type设值时,其值为HOME。  
另外,一个proto文件中可以声明多个message,在编译的时候他们会被编译成为不同的类。

3.proto生成C++文件

protoc是proto文件的编译器,目前可以将proto文件编译成C++、Java、Python三种代码文件,编译格式如下:

protoc -I=$SRC_DIR --cpp_out=$DST_DIR /path/to/file.proto

如:

protoc -I=/Users/yanhe/Desktop/ --cpp_out=/Users/yanhe/Desktop/ /Users/yanhe/Desktop/pro.proto

生成oc文件

protoc --proto_path="proto文件位置" --objc_out="输出位置" "proto文件名字"

4.使用proto生成的C++文件

编写一个c++文件来使用proto文件:

#include <iostream>

#include "pro.pb.h"

int main(int argc, const char* argv[])

{

addressbook::AddressBook person;

addressbook::Person* pi = person.add_person_info();

pi->set_name("aut");

pi->set_id(1219);

std::cout << "before clear(), id = " << pi->id() << std::endl;

pi->clear_id();

std::cout << "after clear(), id = " << pi->id() << std::endl;

pi->set_id(1087);

if (!pi->has_email())

pi->set_email("autyinjing@126.com");

addressbook::Person::PhoneNumber* pn = pi->add_phone();

pn->set_number("021-8888-8888");

pn = pi->add_phone();

pn->set_number("138-8888-8888");

pn->set_type(addressbook::Person::MOBILE);

uint32_t size = person.ByteSize();

unsigned char byteArray[size];

person.SerializeToArray(byteArray, size);

addressbook::AddressBook help_person;

help_person.ParseFromArray(byteArray, size);

addressbook::Person help_pi = help_person.person_info(0);

std::cout << "*****************************" << std::endl;

std::cout << "id: " << help_pi.id() << std::endl;

std::cout << "name: " << help_pi.name() << std::endl;

std::cout << "email: " << help_pi.email() << std::endl;

 

for (int i = 0; i < help_pi.phone_size(); ++i)

{

auto help_pn = help_pi.mutable_phone(i);

std::cout << "phone_type: " << help_pn->type() << std::endl;

std::cout << "phone_number: " << help_pn->number() << std::endl;

}

std::cout << "*****************************" << std::endl;

 

return 0;

}

5.常用的API

protoc为message的每个required字段和optional字段都定义了以下几个函数(不限于这几个):

TypeName xxx() const;          //获取字段的值
2 bool has_xxx();              //判断是否设值
3 void set_xxx(const TypeName&);   //设值
4 void clear_xxx();          //使其变为默认值

为每个repeated字段定义了以下几个:

TypeName* add_xxx();        //增加结点
2 TypeName xxx(int) const;    //获取指定序号的结点,类似于C++的"[]"运算符
3 TypeName* mutable_xxx(int); //类似于上一个,但是获取的是指针
4 int xxx_size();            //获取结点的数量

另外,下面几个是常用的序列化函数:

1 bool SerializeToOstream(std::ostream * output) const; //输出到输出流中
2 bool SerializeToString(string * output) const;        //输出到string
3 bool SerializeToArray(void * data, int size) const;   //输出到字节流

与之对应的反序列化函数:

1 bool ParseFromIstream(std::istream * input);     //从输入流解析
2 bool ParseFromString(const string & data);       //从string解析
3 bool ParseFromArray(const void * data, int size); //从字节流解析

其他常用的函数:

1 bool IsInitialized();    //检查是否所有required字段都被设值
2 size_t ByteSize() const; //获取二进制字节序的大小

官方API文档地址: https://developers.google.com/protocol-buffers/docs/reference/overview

6. 编译生成可执行代码 

  编译格式和普通的C++代码一样,但是要加上 -lprotobuf -pthread 

1 g++ main.cc xxx.pb.cc -I $INCLUDE_PATH -L $LIB_PATH -lprotobuf -pthread 

 

 

转载于:https://my.oschina.net/HeroOneHY/blog/1632362

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值