google protobuf_protobuf 入门教程

87aa90da-9ac7-4055-982b-44afebb8dce2

应用Proto buffers

protobuf简介

google开源的protobuf,是工业界常用的序列化、反序列化代码库。常用于RPC、服务器与客户端、消息队列、数据格式化等场景。其优点是:高效率的序列化、反序列化,二进制数据格式紧凑,易上手,支持多种编程语言。

快速上手

1,定义.proto文件

在addressbook.proto中定义,消息AddressBook消息格式。

//版本2的消息格式syntax = "proto2";//消息属于包或命名空间package tutorial;//定义Person消息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 phones = 4;}//定义AddressBook消息message AddressBook { repeated Person people = 1;}

关键字说明:

  • package 命名空间
  • message 消息体关键字,类似C语言中的struct
  • enum 枚举类型

字段修饰符:

  • required 消息中必须要填充的字段。
  • optional 消息中可填可不填的字段
  • repeated 定义消息数组,数组长度可变
  • 官方文档建议用 optional repeated 而不是 required

等号后的数字是字段编号:

required string name = 1;

字段编号的意义:

each field in the message definition has a unique number. These numbers are used to identify your fields in the message binary format, and should not be changed once your message type is in use. Note that field numbers in the range 1 through 15 take one byte to encode, So you should reserve the field numbers 1 through 15 for very frequently occurring message elements. The smallest field number you can specify is 1, and the largest is 2^29 - 1, or 536,870,911.

可选字段的默认值:

optional PhoneType type = 2 [default = HOME];

当可选字段没被指定时,用其默认值。

If the default value is not specified for an optional element, a type-specific default value is used instead: for strings, the default value is the empty string. For bytes, the default value is the empty byte string. For bools, the default value is false. For numeric types, the default value is zero. For enums, the default value is the first value listed in the enum's type definition.

注意enum类型中,等号后面的值就是具体的值,而不是字段编号

enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2;}

2,编译.proto

执行编译命令

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

${DST_DIR}中生成addressbook.pb.cc,addressbook.pb.h。

在addressbook.pb.h定义了Person,Person_PhoneNumber和AddressBook类。 在类中定义了,各个字段的访问函数。相同数据类型的字段,其访问函数形式类似。

函数名称中基本都含有字段名。

1,string类型变量

required string name = 1;bool has_name() const; void clear_name(); static const int kNameFieldNumber = 1; const ::std::string& name() const; void set_name(const ::std::string& value); #if LANG_CXX11 void set_name(::std::string&& value); #endif void set_name(const char* value); void set_name(const char* value, size_t size);::std::string* mutable_name();::std::string* release_name(); void set_allocated_name(::std::string* name);

2,int32类型

required int32 id = 2;bool has_id() const; void clear_id(); static const int kIdFieldNumber = 2;::google::protobuf::int32 id() const;void set_id(::google::protobuf::int32 value);

3,repeated 类型

repeated PhoneNumber phones = 4;int phones_size() const;void clear_phones(); static const int kPhonesFieldNumber = 4;::tutorial::Person_PhoneNumber* mutable_phones(int index);::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones(); const ::tutorial::Person_PhoneNumber& phones(int index) const;::tutorial::Person_PhoneNumber* add_phones(); const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;

3,常用操作函数

标准操作方法

  • bool IsInitialized() const; 所有required域是否被设置;
  • string DebugString() const;: 输出可读性好的串
  • void CopyFrom(const Person& from);: 用对象填充消息
  • void Clear();: 清理

序列化方法

  • bool SerializeToString(string* output) const;: => 二进制
  • bool ParseFromString(const string& data);: <= 二进制
  • bool SerializeToOstream(ostream* output) const;: => ostream
  • bool ParseFromIstream(istream* input);: <= ostream

热身在即

4,应用实例

实例解析。从命令行读取用户的输入的Person信息,填充AddressBook对象,填充完成后,序列化并写入二进制文件。

注:google protobuf的编译安装,请参见:https://github.com/protocolbuffers/protobuf/blob/master/src/README.md

/*main.cpp编译:g++ -g -I. -std=c++11 -o write addressbook.pb.cc main.cpp `pkg-config --cflags --libs protobuf` /usr/local/lib/libprotobuf.a -lpthread*/#include #include #include #include "addressbook.pb.h"using namespace std;// This function fills in a Person message based on user input.void PromptForAddress(tutorial::Person* person) { cout << "Enter person ID number: "; int id; cin >> id; person->set_id(id); cin.ignore(256, ''); cout << "Enter name: "; getline(cin, *person->mutable_name()); cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty()) { person->set_email(email); } while (true) { cout << "Enter a phone number (or leave blank to finish): "; string number; getline(cin, number); if (number.empty()) { break; } tutorial::Person::PhoneNumber* phone_number = person->add_phones(); phone_number->set_number(number); cout << "Is this a mobile, home, or work phone? "; string type; getline(cin, type); if (type == "mobile") { phone_number->set_type(tutorial::Person::MOBILE); } else if (type == "home") { phone_number->set_type(tutorial::Person::HOME); } else if (type == "work") { phone_number->set_type(tutorial::Person::WORK); } else { cout << "Unknown phone type. Using default." << endl; } }}// Main function: Reads the entire address book from a file,// adds one person based on user input, then writes it back out to the same// file.int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!input) { cout << argv[1] << ": File not found. Creating a new file." << endl; } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } // Add an address. PromptForAddress(address_book.add_people()); { // Write the new address book back to disk. fstream output(argv[1], ios::out | ios::trunc | ios::binary); if (!address_book.SerializeToOstream(&output)) { cerr << "Failed to write address book." << endl; return -1; } } cout << "Debug:" <

从序列化的文件中读入AddressBook信息,并显示。

/*read.cpp编译:g++ -g -I. -std=c++11 -o read addressbook.pb.cc read.cpp `pkg-config --cflags --libs protobuf` /usr/local/lib/libprotobuf.a -lpthread*/#include #include #include #include "addressbook.pb.h"using namespace std;// Iterates though all people in the AddressBook and prints info about them.void ListPeople(const tutorial::AddressBook& address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person& person = address_book.people(i); cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.has_email()) { cout << " E-mail address: " << person.email() << endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber& phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: cout << " Mobile phone #: "; break; case tutorial::Person::HOME: cout << " Home phone #: "; break; case tutorial::Person::WORK: cout << " Work phone #: "; break; } cout << phone_number.number() << endl; } } }// Main function: Reads the entire address book from a file and prints all// the information inside.int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } ListPeople(address_book); cout << "Debug:" <
66c244fef7ff44e294ecf6987871eba5

扫码关注

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值