protobuf入门address_book实例——个人实战感想记录

一、 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

二、实例

Protobuf使用实例

Protobuf例子

  • 我对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()

可以参考——C++11新特性之基本范围的For循环(range-based-for)

猜你喜欢

转载自blog.csdn.net/weixin_48622537/article/details/110789258
今日推荐