Google protocol buffer 笔记

Google protocol buffer

 

       Googleprotocol buffer 可以理解为一种数据描述语言,类似于XML,但比XML小巧,快速。

       使用 Google protocol buffer 需要下载其完整源码包编译,最后需要的是其头文件、库、以及相应的protoc.exe编译引擎。

       需要的头文件通常在源码解压缩后的文件夹中的[dst]\src\google\protobuf下,通常只要拷贝整个[dst]\src\google目录即可, [dst] 为解压源码压缩包的目录。

protocol buffer库以及protoc.exe需要通过编译产生,在 [dst]\vsprojects 目录下有相应的对应于VS 的 .sln 工程文件,用VS 编译即可得到编译引擎protoc.exe和所需的三个库文件:libprotobuf.lib libprotobuf-lite.liblibprotoc.lib, 将编译引擎至于系统目录system32下或者放置在其他路径,然后将该路径添加至系统环境变量PATH 中即完成了相应的环境配置。

       为了使用Google protocol buffer 来定义自己的数据,需按照相应语法将内容写入一个.proto文件中,然后使用 protoc.exe编译 .proto 文件,得到一个头文件 .pb.h 和一个 .pb.cc文件,使用这两个文件即可使用自己的数据结构。通常需要上边编译得到的三个库,将其放置于某一个目录并包含即可,头文件亦是。

protoc.exe 编译的命令行形式是

 

protoc-I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

或简单的

protoc –cpp_out=dir*.proto

 

更多的参数设置可以参考自带的帮助信息(命令行下 protoc –h 或者 protoc --help)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.proto文件语法与格式说明

package tutorial;

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;

}

messageAddressBook {

  repeated Person person = 1;

}

 

package tutorial; // 声明包,表明此声明下方的数据结构都属于此包, package起到命名空间的作用避免变量命名冲突,使用protoc.exe编译.proto文件后,package名即转换为相应的命名空间,定义Person类的对象时语法应为 tutorial::Person pr;

 

定义在message A里边的message B在protoc.exe编译后,会成为package 下的两个平行的类,但message B对应的类名变成了 A_B; 然后在message A对应的类A中会存在一个typedef, 即 typedef A_B B. 因此,在定义和调用类B的对象时,既可以使用package::A::B 也可以使用package::A_B;但对于某些需要类前置声明的地方,则只能够使用package::A_B

 

定义在message A中的共用体(enum)类型 C, 编译后会成为package下的一个共用体,名为A_C, 而共用体中的变量名X 、Y则相应的被重定义为 A_C_X、A_C_Y;在类中使用typedef 将 A_C 定义为 C, 即 typedefA_C  C; 然后用一组静态常量重定义A_C中的变量

  static constPhoneType MOBILE = Person_PhoneType_MOBILE;

  static constPhoneType HOME = Person_PhoneType_HOME;

  static constPhoneType WORK = Person_PhoneType_WORK;

 

message中的每一个成员都必须使用域规则(field rules)required、optional、repeated 三者之一作为前置声明。

required 修饰的成员必须被赋值,如果libprotobuf 在debug模式下编译,那么对包含未初始化的repeated成员的对象进行序列化的时候将会失败,如果libprotobuf经过优化编译,那么序列化会继续进行而不产生错误,但对序列化后的数据进行解析会失败。

对于optional 成员,其值可以不被初始化,但在可行的时候应为optional 成员设定默认值。如果没有默认值,那么系统会自动为optional成员添加默认值,对于数值类型,默认值是0;对于字符串类型,默认为空串;bool类型默认值为false。对于嵌套的message,其默认值为默认的对象或原型,即未初始化的对象。访问默认对象的成员得到的将是系统默认值。

repeated成员意味着可以包含多个此类型的成员(也可以是0个)。

 

对于message中的required 和optional 变量var,使用相应的set_var函数对成员变量赋值;对于repeated 变量 revar, 使用 add_revar 函数进行赋值。

 

required 、optional、 repeated 规则控制的变量赋值演示

tutorial::Person::PhoneNumber * pn =vpm.add_phone();// vpm 为 People 类型 phone is repeated variable

     pn->set_number("15*********9");  // number is required variable

     pn->set_type(tutorial::Person::MOBILE);// type is optional variable

 

对于已经赋值(或者说完成初始化)的对象A,调用其required与optional成员a的方式即A.a(). 而repeated成员b的调用方式则是A.b(int index), index为索引。 如果repeated成员b的类型是一个复合类型,即包含多个成员的结构体或者类,那么只需继续使用成员操作符(.)来获取相应的成员,

 

对于任意类型的成员var, 都可以通过 have_var() 来判断成员变量是否已经赋值;通过clear_var() 来清除变量内容;对于对象,可以通过 IsInitialized()函数判断required类型成员是否全部初始化;使用clear()清理对象的所有成员。对于repeated成员b,b_size()函数可以用来获取b成员的个数。

 

对于string成员S,使用mutable_S()函数将使得你得到直接指向该成员的指针(direct pointer),而无论该成员是否已经初始化。

 

message 成员的类型可以是基础类型boolint32floatdoublestring也可以是复杂的自定义类型,自定义类型可以嵌套。更详细的类型支持列表:http://code.google.com/apis/protocolbuffers/docs/proto.html

 

成员尾部的 =1、 =2 在进行二进制编码时作为唯一标志符的作用,标志符数字小于15的成员使用一个字节进行编码,而标志符数字在16~2047的成员使用两个字节进行编码。因此,在成员很多的时候,应将required或者repeated成员的标志符数字安排在1~15;而将不常用的optional成员安排在16及更大的数字,这样将产生很好的优化效果。可以被使用的最小的标记符数字是1,最大的是536,870,911(2^29 -1)。数字在19000~19999之间的数字是保留给protocol buffer 使用的,如果你在定义自己的message是使用了将会导致编译错误。对于repeated 域规则制定的数值类型成员,须使用[packed=true]才能进行较为优化的编码。示例: repeated int32 samples = 4[packed=true];

 

 

解析与序列化(使用二进制方式读写message)

·         bool SerializeToString(string* output) const;: serializes the message and stores the bytes in the given string. Notethat the bytes are binary, not text; we only use the string class as a convenient container.

·         bool ParseFromString(const string& data);: parses a message from the given string.

·         bool SerializeToOstream(ostream* output) const;: writes the message to the given C++ ostream.

·         bool ParseFromIstream(istream* input);: parses a message from the given C++ istream.

实例参考:http://code.google.com/apis/protocolbuffers/docs/cpptutorial.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值