c++使用proto文件方法简介

来源:互联网 发布:vb中大于等于怎么表示 编辑:程序博客网 时间:2024/05/12 07:30

GoogleProtocol Buffers 简称 Protobuf,是 Google 公司内部的混合语言数据标准.它提供一种轻量,高效的结构化数据存储结构.

简介

为什么要使用protobuf?

1.   官方文档中提到一些protobuf的优点, protobuf灵活高效的结构化数据存储格式.方便用于序列化, 适合做RPC的数据交换.

2.   相比 XML , protobuf 比 XML 更小、更快、更简单.仅需要写一个 *.proto 文件描述需要的数据结构, protobuf会帮助你实现相关类和方法(自动化多好!).

3.   目前提供 C++, Java, Python, Go, C#等多种语言 的API

 

安装

在ubuntu上一键安装

sudoapt-get install protobuf-compiler

 

定义proto文件

定义proto文件较为简单,给每个结构体数据定义一个message,然后给结构体中的每个数据添加一个类型和名称,例如,想要定义一个address.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;}message AddressBook {  repeated Person person = 1;}

有如你所见,消息格式很简单,每个消息类型拥有一个或多个特定的数字字段,每个字段拥有一个名字和一个值类型。值类型可以是数字(整数或浮点)、布尔型、字符串、原始字节或者其他ProtocolBuffer类型,还允许数据结构的分级。你可以指定可选字段,必选字段和重复字段。

一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的 .proto 文件编译成特定语言的类。这些类提供了简单的方法访问每个字段(像是 query()和 set_query() ),像是访问类的方法一样将结构串行化或反串行化。

编译proto文件

现在已经拥有了 .proto文件,下一步就是编译生成相关的访问类。运行编译器 protoc 编译你的 .proto文件。

1.   如果还没安装编译器则下载并按照README的安装。

2.   运行编译器,指定源目录和目标目录,定位你的 .proto文件到源目录,然后执行:

protoc-I=$SRC_DIR –cpp_out=$DST_DIRaddressbook.proto

此操作生成c++格式的proto文件,如果想生成Python、java等类型的,把cpp换成python、java等即可,该操作生成如下两个文件:

addressbook.pb.h    定义了c++的头文件

addressbook.pb.cc   包含了类的实现

 

protocol buffer API

编译后的name、id、emal、和phone有如下方法:

// name  inline bool has_name() const;  inline void clear_name();  inline const ::std::string& name() const;  inline void set_name(const ::std::string& value);  inline void set_name(const char* value);  inline ::std::string* mutable_name();  // id  inline bool has_id() const;  inline void clear_id();  inline int32_t id() const;  inline void set_id(int32_t value);  // email  inline bool has_email() const;  inline void clear_email();  inline const ::std::string& email() const;  inline void set_email(const ::std::string& value);  inline void set_email(const char* value);  inline ::std::string* mutable_email();  // phone  inline int phone_size() const;  inline void clear_phone();  inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phone() const;  inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phone();  inline const ::tutorial::Person_PhoneNumber& phone(int index) const;  inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);  inline ::tutorial::Person_PhoneNumber* add_phone();

如你所见,获取字段的方法都是字段名称的小写,如

inline const ::std::string& name()const;inline int32_t id()const;inline const ::std::string& email()const;inline const ::tutorial::Person_PhoneNumber& phone(int index) const;

设置字段名称的方法都已set_开头,singular (required or optional) 类型的字段有has_开头的方法,如果该字段已经设置了,那么该方法返回true

最后,每个字段都有一个clear_方法来把字段复位为空状态

 

数字类型的字段id只有基本的设置字段的方法,string型的字段name和email有几个其他的方法,mutable_开头的方法让你得到一个直接指向string类型的指针,及时email未被设置,你也可以调用mutable_email(),它将会自动初始化为一个空的string。如果字段在调用这个方法之前没有被设置,那么返回的字符串将为空(而不是缺省值)。调用这个方法后,has_foo()返回 true,foo()返回被写入到字符串(foo)中的任何值。通过调用 Clear()或 clear_foo()清除此指针。

 

Repeated类型的字段有一些特殊的方法

_size:检查有多少个字段

使用index来获取特定的字段

更新一个已经存在的字段

add_方法添加一个新的字段

 

生成的代码包含一个PthonType枚举,可以通过Person::PthonType或者它们的值Person::MOBILE, Person::HOME,和Person::WORK来调用它们.

 

标准消息方法

每个消息还包括一些其他方法用来检查和操作整个消息

bool IsInitialized() const; //检查是否所有的requied类型的消息都被设置了string DebugString() const;//返回消息的一个可读类型,debug时很有用void CopyFrom(const Person& from);//用给定的值来覆盖消息void Clear();//把所有元素置回空状态


解析和序列化

最终,protocol buffer类有使用二进制格式来读写消息的方法:

bool SerializeToString(string* output) const;//序列化消息并把字节存储在给定的string类型中,注意字节是二进制类型,而不是text类型,我们只是使用string类型作为一个转换容易bool ParseFromString(const string& data);//从string中解析消息bool SerializeToOstream(ostream* output)const;//把消息写入一个给定的c++ostream中bool ParseFromIstream(istream* input);//从一个给定的c++ istream中解析消息





0 0
原创粉丝点击