一、 protoc编译proto文件
protoc是proto文件的编译器,目前可以将proto文件编译成C++、Java、Python三种代码文件,编译格式如下:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR /path/to/file.proto
上面的命令会生成addressbook.pb.h 和 addressbook.pb.cc两个C++文件。
推荐在src文件夹内编译
protoc --cpp_out=. addressbook.proto
二、实例
- 我对address_book实例的编译
//proto文件
//把proto文件转化成c++代码.执行下面命令.
//protoc --cpp_out=. addressbook.proto
syntax = "proto2";
package addressbook;
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;
}
message AddressBook {
repeated Person person_info = 1;
}
//writer
#include <iostream>
#include"../src/addressbook.pb.h"//地址根据你的头文件而定
#include <fstream>
#include<iconv.h>
int main()
{
//定义信息类
addressbook::AddressBook person;
addressbook::Person* pi = person.add_person_info();
//检验是否已经存在信息接受文件
std::fstream input("../../txt.prototxt", std::ios::in | std::ios::binary);
if (!input) {
std::cout << "../../txt.prototxt"
<< ": File not found. Creating a new file."
<< std::endl;
}
else if (!person.ParseFromIstream(&input)) {
std::cerr << "Failed to parse address book." << std::endl;
return -1;}
//设置初值
pi->set_name("aut");
pi->set_id(1087);
if (!pi->has_email())
pi->set_email("[email protected]");
addressbook::Person::PhoneNumber* pn = pi->add_phones();
pn->set_number("021-8888-8888");
pn = pi->add_phones();
pn->set_number("138-8888-8888");
pn->set_type(addressbook::Person::MOBILE);
//打开(新建)文件进行信息输出
std::fstream output("../../txt.prototxt", std::ios::out | std::ios::trunc | std::ios::binary);
if (!person.SerializeToOstream(&output)) {
std::cerr << "Failed to write address book." << std::endl;
return -1;}
return 0;
}
此种reader方式,对于repeated信息的处理,不是很简介,不推荐,但是可以帮助大家理解接受信息,并打印的原理。
//reader1
#include <iostream>
#include"../src/addressbook.pb.h"//根据头文件地址而定
#include<fstream>
#include<iconv.h>
#include<string>
int main()
{
//定义信息类准备接收信息
addressbook::AddressBook help_person;
//打开文件进行 读 操作
std::fstream input("../../txt.prototxt",std::ios::in | std::ios::binary);
if(!help_person.ParseFromIstream(&input)){
std::cerr << "Failed to parse address book." << std::endl;
return -1;
}
//由于这个项为repeated,可以理解为一个vector
auto help_pi=help_person.person_info();
std::cout << "*****************************" << std::endl;
std::cout << "id: " << help_pi[0].name() << std::endl;
std::cout << "name: " << help_pi[0].id() << std::endl;
std::cout << "email: " << help_pi[0].email() << std::endl;
auto number1=help_pi[0].add_phones();
std::cout << "email: " << number1[0].number() << std::endl;
std::cout << "*****************************" << std::endl;
return 0;
}
此种reader方式,对于repeated信息的处理很简洁,但是这个种处理方式是C++11才有的,可以参考这一篇文章——C++11新特性之基本范围的For循环(range-based-for)
//reader2
#include <iostream>
#include"../src/addressbook.pb.h"
#include<fstream>
#include<iconv.h>
#include<string>
int main()
{
//从内存中读取并反序列化
addressbook::AddressBook help_person;
std::fstream input("../../txt.prototxt",std::ios::in | std::ios::binary);
if(!help_person.ParseFromIstream(&input)){
std::cerr << "Failed to parse address book." << std::endl;
return -1;}
//通过Range-Based-For 的方式进行遍历读取
for(addressbook::Person help_pi:help_person.person_info())
{
std::cout<<help_pi.name()<<std::endl;
std::cout<<help_pi.id()<<std::endl;
std::cout<<help_pi.email()<<std::endl;
for(addressbook::Person::PhoneNumber help_pn:help_pi.phones())
{
std::cout << "phone_type: " << help_pn.type() << std::endl;
std::cout << "phone_number: " << help_pn.number() << std::endl;
}
}
return 0;
}
三、解决protobuf的Undefined reference to google::protobuf cxx11
在.pro文件中加入LIBS += /usr/local/lib/libprotobuf.so
即可
四、C++版本的protubuf有几种serialize和unSerialize的方法:
Protobuf C++ serialize到char*的方法
五、写protobuf的大体思路
- writer
首先定义信息类
传入(或输入)初值
打开并输出信息文件
- reader
首先打开信息文件
定义信息类进行接收
打印
PS:不能先定义信息类,再打开信息文件,因为这样就会导致信息没有接收对象了
程序中可能会用到tutorial::Person people:address_book.people()