当前位置:   article > 正文

protobuf使用实例_google.protobuf.any

google.protobuf.any

一、描述proto文件

  proto文件名称为addressbook.proto。

syntax = "proto3";
import "google/protobuf/any.proto";

// package类似于namespace,可以避免命名冲突
package AddressBookInfo;

// message类似于class
message Person
{
    string name = 1;
    int32 id = 2;
    string email = 3;
    
    // 枚举类型
    enum PhoneType
    {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
    
    message PhoneNumber
    {
        string number = 1;
        // proto3中enum没有default选项,把第一个值作为default
        PhoneType type = 2;
    }
    
    // repeated表示message或者filed可以重复多次
    repeated PhoneNumber phones = 4;
}

message Address
{
	string address = 1;
}

message AddressBook
{
    string owner = 1;
    repeated Person person_infos = 2;

    /* 
    ** oneof类似于union类型,某一个时刻只能设置一个field,所有的field共享同一段内存。
    ** 设置oneof字段将自动清除oneof的所有其他字段,即只能同时设置(set_)一个,不然就会core dump。
    ** 可以在oneof内部添加和删除field,但是删除和添加oneof要小心。
    ** oneof中数据成员的编号建议承上启下,尽量不要随意编号。
    */
    oneof PayType
    {
        string type_ali = 3;
        string type_wx = 4;
    }

    /*
    ** map是key-value类型,key可以是int或者string,value可以是自定义message。
    ** Any用来实现泛型,可以表示任意类型。
    */
    map<string, google.protobuf.Any> owner_address = 5;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

二、编译proto文件

  使用protoc编译器对proto文件进行编译,生成addressbook.pb.haddressbook.pb.cc
在这里插入图片描述

三、生成protobuf API

  打开addressbook.pb.haddressbook.pb.cc,可以看到自动生成了很多的API,后续可以使用这些API读写数据。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、使用API写入和读取数据

  addressbook.cpp文件中阐述了如何使用protobuf自动生成的API读写数据,基本上覆盖了常用的消息类型。

  具体的API及使用方式可以参考:https://developers.google.cn/protocol-buffers/docs/reference/cpp-generated

#include <iostream>
#include <fstream>
#include "addressbook.pb.h"
#include <google/protobuf/any.h>

using namespace std;

void SaveInfo()
{
	AddressBookInfo::AddressBook adbook;

	// 使用set_设置message中filed的值,函数名都是小写(即使在proto中是大写)
	adbook.set_owner("eric");

	// Person1
	// 使用add_添加message,返回的是指针类型
	AddressBookInfo::Person *person1 = adbook.add_person_infos();
	person1->set_name("mark");
	person1->set_id(123456);
	person1->set_email("mark@163.com");

	AddressBookInfo::Person::PhoneNumber *person1_phone = person1->add_phones();
	person1_phone->set_number("12345678");
	// 枚举类型中的元素名称是唯一的,所以可以直接用作用域限定符访问元素,不需要通过枚举名访问
	person1_phone->set_type(AddressBookInfo::Person::HOME);

	person1_phone = person1->add_phones();
	person1_phone->set_number("1234");
	person1_phone->set_type(AddressBookInfo::Person::WORK);

	// Person2
	AddressBookInfo::Person *person2 = adbook.add_person_infos();
	person2->set_name("mike");
	person2->set_id(654321);
	person2->set_email("mike@163.com");

	AddressBookInfo::Person::PhoneNumber *person2_phone = person2->add_phones();
	person2_phone->set_number("87654321");
	person2_phone->set_type(AddressBookInfo::Person::HOME);

	person2_phone = person2->add_phones();
	person2_phone->set_number("5678");
	person2_phone->set_type(AddressBookInfo::Person::WORK);

	// map和any类型的初始化,mutable返回的是非const指针类型
	google::protobuf::Map<string, google::protobuf::Any> *owner_address = adbook.mutable_owner_address();
	// 定义一个Any类型,用于接收message
	google::protobuf::Any *any = new google::protobuf::Any;
	AddressBookInfo::Address adbook_address;
	adbook_address.set_address("HB");
	// 使用PackFrom将message类型存储为Any类型
	any->PackFrom(adbook_address);
	// map类型的初始化方式和STL中的map类似
	(*owner_address)[adbook.owner()] = *any;

	// 设置oneof中某一个成员的值,之后如果再使用set_则会core dump
	adbook.set_type_ali("AliPay");

	fstream output("address_book_file", ios::out | ios::trunc | ios::binary);
	// 使用SerializeToOstream将序列化后的数据写入文件中
	if (!adbook.SerializeToOstream(&output))
	{
		cerr << "Failed to write address book." << endl;
	}
}

void ShowMsg(const AddressBookInfo::AddressBook &adbook)
{
	cout << adbook.owner() << endl;
	// 对于重复message,_size表示有多少个重复message,使用索引取出每一个message
	for (int i = 0; i < adbook.person_infos_size(); ++i)
	{
		const AddressBookInfo::Person &person = adbook.person_infos(i);
		// 取出各个字段的值
		cout << person.name() << endl;
		cout << person.id() << endl;
		cout << person.email() << endl;
		for (int j = 0; j < person.phones_size(); ++j)
		{
			// 使用索引获取枚举类型的所有值
			const AddressBookInfo::Person::PhoneNumber &person_phone = person.phones(j);
			switch(person_phone.type()) 
			{
				case AddressBookInfo::Person::MOBILE :
					cout << "MOBILE phone #: ";
					break;
				case AddressBookInfo::Person::HOME :
					cout << "HOME phone #: ";
					break;
				case AddressBookInfo::Person::WORK :
					cout << "WORK phone #: ";
					break;
			}
			cout << person_phone.number() << endl;
		}
	}
	cout << adbook.type_ali() << endl;
}

void ShowMapMsg(const AddressBookInfo::AddressBook &adbook) 
{
	// 取出map类型的字段成员
	const google::protobuf::Map<string, google::protobuf::Any> &adbook_map = adbook.owner_address();
	// 使用迭代器访问map(和STL中的map类似)
	auto iter = adbook_map.begin();
	cout << iter->first << endl;
	google::protobuf::Any any = iter->second;
	AddressBookInfo::Address adbook_address;
	// 使用UnpackTo从Any类型解析出message,注意参数中有一个&
	if (any.UnpackTo(&adbook_address))
	{
		cout << adbook_address.address() << endl;
	}
	else
	{
		cout << "UnpackTo data error" << endl;
	}
}

void LoadInfo()
{
	AddressBookInfo::AddressBook adbook;
	fstream input("address_book_file", ios::in | ios::binary);
	// 使用ParseFromIstream从文件中反序列化
	if (!input)
	{
		cout << ": File not found.  Creating a new file." << endl;
	}
	else if (!adbook.ParseFromIstream(&input))
	{
		cout << "Failed to parse address book." << endl;
	}
	ShowMsg(adbook);
	cout << endl;
	ShowMapMsg(adbook);
}

int main(int argc, char const *argv[])
{
	SaveInfo();
	LoadInfo();
	// 删除所有已分配的内存(注意any是堆上的内存,清除内存的操作要小心)
	google::protobuf::ShutdownProtobufLibrary();
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

五、编译所有的CPP文件

  使用g++编译所有的CPP文件,注意编译参数需要加上:-std=c++11、-lprotobuf、-lpthread
在这里插入图片描述
在这里插入图片描述

六、编译和运行中遇到的问题

  (1)如果没有添加-std=c++11选项则会出现以下问题:
在这里插入图片描述
  (2)针对oneof类型,如果同时设置了多个字段或者字段编号混乱,则会出现以下问题:
在这里插入图片描述

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

闽ICP备14008679号