当前位置:   article > 正文

ProtoBuf安装和使用简介_protobuf.git

protobuf.git

在前一篇文章中,对ProtoBuf做了一个基本介绍,这篇文章主要介绍ProtoBuf的安装和使用。

ProtoBuf的安装

安装ProtoBuf前需要先安装ProtoBuf的编译器和运行时环境。

对于C++使用者:由于ProtoBuf是用C++写的,因此你可以获取ProtoBuf的源码自己编译,而对于其他语言来说可以直接使用ProtoBuf已经编译好的Release版本直接进行安装和使用,相比来说使用Release版本会方便很多。

ProtoBuf在Git上的地址是:https://github.com/google/protobuf.git, 你可以clone源码然后按照ReadMe文件自己编译。

获取Release版本的地址是:https://github.com/google/protobuf/releases 你可以从这个地址下载你所需要的安装包,注意使用C++编程的话下载cpp的包,其他语言对应选择,本文介绍了Linux下安装和使用ProtoBuf.

1、下载ProtoBuf的压缩包protobuf-cpp-3.0.0-beta-3.tar.gz 随便哪个版本都行

     将安装包拷贝到你的Linux机器上,进入所在目录,利用tar命令将该文件解压缩到当前文件夹。

    加压后你可以再该目录下找到ReadME文件,这个文件就介绍了如何安装ProtoBuf,安装这部分基本是对该文件的一个中文翻译,英文水平好的可以直接参照该文件安装

2、安装ProtoBuf

   $ ./configure
   $ make
   $ make check
   $ sudo make install
   $ sudo ldconfig # refresh shared library cache.

进入你解压后的目录,依次执行以上命令,如果命令都执行成功,说明ProtoBuf安装成功。通常情况ProtoBuf都安装在/usr/local目录下,该目录下包含了ProtoBuf的头文件,静态库和动态库文件



如何使用ProtoBuf

ProtoBuf安装完成后,就可以按照上一篇文章介绍的步骤去使用ProtoBuf。(定义你自己的ProtoBuf源文件,用ProtoBuf编译器编译该源文件)

在本节内容中引用了Google官网中关于ProtoBuf使用的电话本的例子来介绍ProtoBuf的使用。


定义一个ProtoBuf源文件,Person.pro

  1. syntax="proto3";
  2. package tutorial;
  3. message Person
  4. {
  5. string name = 1;
  6. int32 id = 2;
  7. string email = 3;
  8. enum PhoneType
  9. {
  10. MOBILE = 0;
  11. HOME = 1;
  12. WORK = 2;
  13. }
  14. message PhoneNumber
  15. {
  16. string number = 1;
  17. PhoneType type = 2;
  18. }
  19. repeated PhoneNumber phone = 4;
  20. }
  21. message AddressBook
  22. {
  23. repeated Person person =1;
  24. }


可以看到该文件中,包含了ProtoBuf结构的嵌套以及使用另外一种自定义的数据类型,Person结构中包含了一个Person联系人的基本信息,包括name, id ,email PhoneNumber

而PhoneNumber又是一个ProtoBuf的结构定义,某个属性被标注为repeated意味着编译后生成的Person对象中可以包含一个或者多个PhoneNumber也就是电话号码,而结构AddressBook中有包含了多个联系人Person 这个不难理解,跟我们实际手机联系人信息差不多,电话本中包含了多个联系人,每个联系人可以有多个电话号码,如家庭电话,手机,工作电话。


编译该源文件

 进图到源文件目录编译该源文件 protoc -I=。   --cpp_out=.  Person.pro

编译后生成Person.proto,pb.h 和Person.pro.pb.cc文件,这两个文件包含了Person以及AddressBook的类,以及对应操作类的方法,在你使用者这些类必须包含头文件,最终可执行文件也必须将cc文件也编译进去。

下面展示使用Person的代码。

add_person.cpp 展示了如何设置一个联系人的各个字段的信息,并且最终序列化信息到文件中。

  1. #include "Person.pro.pb.h"
  2. #include <fstream>
  3. #include <iostream>
  4. using namespace std;
  5. void PromptForAddress(tutorial::Person*);
  6. int main(int argc, char* argv[])
  7. {
  8. GOOGLE_PROTOBUF_VERIFY_VERSION;
  9. if(2 != argc)
  10. {
  11. //必须指定电话本名称才执行程序
  12. cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
  13. return -1;
  14. }
  15. tutorial::AddressBook address_book;
  16. fstream in("ADDRESS_BOOK_FILE", ios::binary | ios::in);
  17. if(!in)
  18. {
  19. cerr << "open file ADDRESS_BOOK_FILE failed!\n";
  20. return -1;
  21. }
  22. if(!address_book.ParseFromIstream(&in))
  23. {
  24. cerr << "Parse File ADDRESS_BOOK_FILE failed!\n";
  25. return -1;
  26. }
  27. in.close();
  28. //增加一个Person,可通过多次调用该接口增加联系人
  29. //具有repeated的属性可通过add_fieldname方法增加一个属性
  30. PromptForAddress(address_book.add_person());
  31. fstream out("ADDRESS_BOOK_FILE", ios::binary | ios::out | ios::trunc);
  32. if(!address_book.SerializeToOstream(&out))
  33. {
  34. cerr << "Failed to Write Address Book!\n";
  35. return -1;
  36. }
  37. //可选的,回收所有ProtoBuf分配的对象
  38. google::protobuf::ShutdownProtobufLibrary();
  39. return 0;
  40. }
  41. void PromptForAddress(tutorial::Person* person)
  42. {
  43. cout<<"Enter a Person ID number: ";
  44. int id;
  45. cin >> id;
  46. person->set_id(id);
  47. /*忽略CIN的前256个字符,或者忽略CIN的换行符之前的字符,包括换行符
  48. 这样的话不会将换行符之前的其他类型的数据保留在输入缓冲中
  49. */
  50. cin.ignore(256, '\n');
  51. cout<<"Enter name: ";
  52. getline(cin, *person->mutable_name());
  53. cout<< "Enter email address (blank for none): ";
  54. string email;
  55. getline(cin,email);
  56. if(!email.empty())
  57. person->set_email(email);
  58. while(true)
  59. {
  60. cout<<"Enter a phone number (or leave blank to finish): ";
  61. string number;
  62. getline(cin, number);
  63. if(number.empty())
  64. break;
  65. tutorial::Person::PhoneNumber* phone_number = person->add_phone();
  66. phone_number->set_number(number);
  67. cout<<"Is this a mobile, home, or work phone? ";
  68. string type;
  69. getline(cin, type);
  70. if(type == "mobile")
  71. phone_number->set_type(tutorial::Person::MOBILE);
  72. else if( type == "home")
  73. phone_number->set_type(tutorial::Person::HOME);
  74. else if (type == "work")
  75. phone_number->set_type(tutorial::Person::WORK);
  76. else
  77. {
  78. cout << "Unknown phone type. Using default." << endl;
  79. phone_number->set_type(tutorial::Person::HOME);
  80. }
  81. }
  82. }

list_cpp展示了如何从文件中读取ProtoBuf序列化的信息

  1. #include "Person.pro.pb.h"
  2. #include <iostream>
  3. #include <fstream>
  4. using namespace std;
  5. void ListPeople(const tutorial::AddressBook& address_book);
  6. int main(int argc, char * argv[])
  7. {
  8. if(2!=argc)
  9. {
  10. cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
  11. return -1;
  12. }
  13. fstream in("ADDRESS_BOOK_FILE", ios::in | ios::binary);
  14. tutorial::AddressBook address_book;
  15. if(!address_book.ParseFromIstream(&in))
  16. {
  17. cerr << "Parse Input File failed!"<< endl;
  18. return -1;
  19. }
  20. ListPeople(address_book);
  21. google::protobuf::ShutdownProtobufLibrary();
  22. return 0;
  23. }
  24. void ListPeople(const tutorial::AddressBook& address_book)
  25. {
  26. //fieldName_size方法返回具有repeated属性的个数
  27. for(int i=0; i< address_book.person_size();i++)
  28. {
  29. const tutorial::Person& person = address_book.person(i);
  30. cout<<"Person ID: "<<person.id();
  31. cout<<"Name: "<<person.name();
  32. cout<<"Email: "<<person.email();
  33. for(int j=0; j< person.phone_size();j++)
  34. {
  35. const tutorial::Person::PhoneNumber& phone_number = person.phone(j);
  36. switch(phone_number.type())
  37. {
  38. case tutorial::Person::MOBILE:
  39. cout << " Mobile phone #: ";
  40. break;
  41. case tutorial::Person::HOME:
  42. cout << " Home phone #: ";
  43. break;
  44. case tutorial::Person::WORK:
  45. cout << " Work phone #: ";
  46. break;
  47. }
  48. cout<<phone_number.number()<<endl;
  49. }
  50. }
  51. }

因为是在Linux下运行的代码,因此写了一个makefile 文件来编译。

test:add_people list_people

add_people:add_person.cpp protoMid
	c++  add_person.cpp Person.pro.pb.cc -o add_people `pkg-config --cflags --libs protobuf`

list_people: list_person.cpp protoMid	
	c++  list_person.cpp Person.pro.pb.cc -o list_people `pkg-config --cflags --libs protobuf`	
protoMid: Person.pro
	protoc -I=. --cpp_out=. ./Person.pro
	
clean:
	rm -f add_people list_people protoMid
	rm -f Person.pro.pb.cc Person.pro.pb.h


执行make后,生成add_people 和list_people两个可执行文件,可以先执行add_people文件增加联系人信息,再执行list_people显示所有联系人信息。


tips:

我在写makefile编译整个源文件时遇到了几个问题,一个是makefile中并没有显示的指定 -i -l 指定编译时需要的头文件地址和链接时需要指定的库文件地址,因此编译链接失败了,有两个方法可以解决该问题,一个是通过-i -l参数指定需要的头文件和库文件地址,另外一个是通过pkg-config 工具, 该工具通过PKG_CONFIG_PATH环境变量指定的地址去找.pc文件,该文件记录了ProtoBuf安装时头文件和库文件所在的目录。 

相比来说,第二种方法要方便很多,但是要注意的是要讲PKG_CONFIG_PATH环境变量设置到正确的地址,否则编译也会失败

$export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/

导出后,编译成功。


本文仅介绍了基本的ProtoBuf的安装和使用过程,对于入门的人来说本文应该能够让读者明白怎么去使用ProtoBuf结构化数据,但对于更加详细的本文没有提及,比如说ProtoBuf2和ProtoBuf3的区别,定义.proto文件的详细语法等,需要了解的可以参考google官方文档









声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/901003
推荐阅读
相关标签
  

闽ICP备14008679号