Google : Protocol Buffers

来源:互联网 发布:java学生信息系统 编辑:程序博客网 时间:2024/06/06 15:53

https://developers.google.com/protocol-buffers/docs/cpptutorial

0. 简介

内容来自引文。

用于将数据序列化、反序列化。比如,想将一个struct存储到文件中(序列化),以后还会读取回来(反序列化)。通常的做法主要有:

  • 最原始的做法是将内存中的数据以二进制形式原封不动的存到文件中,然后在需要的时候直接读回到内存就可以了。但是这么做缺点是:要求序列化、反序列化的语言使用相同的变量内存布局,大小端等。在不同语言之间显然不是很方便了。

  • 编码成字符串。将数据表示成字符串,提供encode和parse方法。

  • 使用xml。xml有很好的可读性,语言支持广泛,是与其他程序共享数据的好方法。缺点是浪费空间、编码/解码效率不高

Google的protobuf可以看做以一个协议,不同的语言都使用相同的协议来序列化、反序列化数据。它的优点是:节省空间、高效。缺点是:听说是可读性差?没体会过,不要相信我。>_<

使用时,只需要提供一个描述文件.proto,然后使用工具protoc就可以自动生成序列化/反序列化的代码。

安装:

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

安装对python的支持:

$ cd ./python$ python setup.py build$ python setup.py test$ sudo python setup.py install

1. 编写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;}

2.编译proto文件

2.1 生成C++的类

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

编译成功后会生成两个文件:

  • addressbook.pb.h, the header which declares your generated classes.
  • addressbook.pb.cc, which contains the implementation of your classes.

2.2 生成Python的类

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

3.使用

3.1 C++写入数据

write.cc

#include <iostream>#include <fstream>#include <string>#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, '\n');  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_phone();    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_person());  {    // 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;    }  }  // Optional:  Delete all global objects allocated by libprotobuf.  google::protobuf::ShutdownProtobufLibrary();  return 0;}

编译&运行:

$ pkg-config --cflags --libs protobuf                                                           -pthread -I/usr/local/include  -pthread -L/usr/local/lib -lprotobuf -lpthread $ g++ write.cc addressbook.pb.cc  -I/usr/local/include  -pthread -L/usr/local/lib -lprotobuf -lpthread $ ./write book

3.2 Python读取数据

read.py

#! /usr/bin/pythonimport addressbook_pb2import sys# Iterates though all people in the AddressBook and prints info about them.def ListPeople(address_book):  for person in address_book.person:    print "Person ID:", person.id    print "  Name:", person.name    if person.HasField('email'):      print "  E-mail address:", person.email    for phone_number in person.phone:      if phone_number.type == addressbook_pb2.Person.MOBILE:        print "  Mobile phone #: ",      elif phone_number.type == addressbook_pb2.Person.HOME:        print "  Home phone #: ",      elif phone_number.type == addressbook_pb2.Person.WORK:        print "  Work phone #: ",      print phone_number.number# Main procedure:  Reads the entire address book from a file and prints all#   the information inside.if len(sys.argv) != 2:  print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"  sys.exit(-1)address_book = addressbook_pb2.AddressBook()# Read the existing address book.f = open(sys.argv[1], "rb")address_book.ParseFromString(f.read())f.close()ListPeople(address_book)
$ ./read.py book...

使用感受

“通过加入一个中间层可以解决任何问题”。原话记不清楚了,但是基本是这个意思。通过引入一个中间层解决问题的例子有很多,比如TCP/IP协议。个人认为Google的Protobuf其实也是引入了一个中间层,这个中间层就是上面提到的描述文件。使用它可以得到其他编程语言的操作代码,而是是让程序员重复的coding,感觉特别聪明。

0 0
原创粉丝点击