当前位置: 首页 > news >正文

【C++】protobuf的简单使用(通讯录例子)

protobuf的简单使用(通讯录例子)

  • .proto文件的编写
    • 保留字段
    • 字段唯一编号
    • protobuf的类型
    • enum类型
    • Any类型
    • oneof类型
    • map类型
    • 完整通讯录代码
      • .proto文件
      • write文件
      • read文件
      • 运行结果

.proto文件的编写

  • syntax用于指定protobuf的语法;
  • package当.proto文件编译后再*.pb.h文件中会形成一个命名空间。
  • message+消息名称:当.proto文件编译后再*.pb.h文件中会形成一个类。

保留字段

  • 可以看到每一个属性后面会有一个数字编号,可以看成属性的唯一标识,用来在消息的二进制格式中标识属性,同一个message域里面不可以使用冲突。定义了就不能修改了,若是想删除,就要将编号添加进reserved保留字段,并且该字段不可继续使用。例如:
message PeopleInfo{//可以单个指定保留字段,也可指定一个范围的保留字段:// 13 to 20 包含13和20。reserved 10, 11, 13 to 20;// 也可指明字段名reserved "gender";string field1 = 10;string field2 = 11;string field3 = 15;string gender = 9;string name = 1;uint32 age = 2;message Phone{string number = 1;enum PhoneType{MP = 0;TEL = 1;}PhoneType type = 2;}repeated Phone phone = 3;google.protobuf.Any data = 4;oneof other_contact{string qq = 5;string wechat = 6;}map<string, string> remark = 7;
}

  如上可以看到,定义了保留字段,编译后如下:
在这里插入图片描述
  表示保留字段不可继续使用。

字段唯一编号

  另外,字段唯一编号范围为:1 ~ 536870911(2^29-1),其中19000 ~ 19999不可用。如果使用了就会告警。
  指定字段唯一编号时,对于使用频繁的字段,将其唯一编号设置为1 ~ 15, 因为1 ~ 15的字段编号只需要一个字节进行编码,16~2047以内的需要2个字节。

protobuf的类型

  .proto Type字段是.proto文件中的字段类型, C++ Type是.proto文件编译后形成的*.pb.h和 *.pb.c文件中的c++对应类型。
在这里插入图片描述
在这里插入图片描述

enum类型

  • enum类型可以定义在消息体内,也可以定义在消息体外。
  • 枚举的常量值在32整数范围内。
  • 0值常量必须存在,且要作为第一个元素。
    在这里插入图片描述
    在这里插入图片描述
  • 同级,也就是同一个作用域中,各个枚举类型中不能定义相同枚举名称:
    在这里插入图片描述

Any类型

   any类型可以理解为泛型类型,可以在any中存储任意数据类型,any类型也可以用repeated修饰。
   在安装protobuf时,include目录下包含了google定义好的.proto文件,在使用any类型时,需要引入any文件,使用import即可。如:
     import "google/protobuf/any.proto";
   定义any类型时,只需使用google.protobuf.Any 当做类型名来定义即可,具体的任意类型和any类型的绑定不在.proto文件中编码。
   例如:
   .proto文件中希望将Address类型转换成any类型:

message Address{string home_address = 1;string unit_address = 2;
}
message PeopleInfo{google.protobuf.Any data = 4;
}

  上面的代码为部分截取。
  在进行序列化的.cc文件中可以这样编写:

Address address;
cout << "请输入家庭地址:";
string home_address;
getline(cin, home_address);
cout << "请输入单位地址:";
string unit_address;
getline(cin, unit_address);address.set_home_address(home_address);
address.set_unit_address(unit_address);// 使用mutable_方法会开辟空间,并且返回一个any指针
// people_info_ptr是PeopleInfo的指针.
google::protobuf::Any *data = people_info_ptr->mutable_data();
PackFrom可以将任意类型转换为any类型。
data->PackFrom(address);
  • 使⽤ PackFrom() ⽅法可以将任意消息类型转为 Any 类型。
  • 使⽤ UnpackTo() ⽅法可以将 Any 类型转回之前设置的任意消息类型
  • 使⽤ Is() ⽅法可以⽤来判断存放的消息类型是否为 typename T。

oneof类型

  顾名思义,就是在众多类型中选择一个类型进行使用。
例如:

oneof other_contact{string qq = 5;string wechat = 6;}
  • oneof中类型的唯一编号,不能和other_contact所在的作用域的编号起冲突,要有唯一性。
  • oneof中不能使用repeated。
  • 在设置oneof中的值的时候,如果多次进行设置值,那么只会保留最后一次设置的值。
  • 获取当前设置了哪一个字段:使用_case方法。

  由于多次进行设置值,那么只会保留最后一次设置的值。这一特性,那么我们在设置oneof值的时候:

cout << "选择一个其他联系方式(1,QQ号     2, 微信号): ";int other_contact;cin >> other_contact;cin.ignore(256, '\n');if(1 == other_contact){cout << "请输入QQ号:";string qq;getline(cin, qq);people_info_ptr->set_qq(qq);}else if(2 == other_contact){cout << "请输入微信号:" ;string wechat;getline(cin, wechat);people_info_ptr->set_wechat(wechat);}else{cout << "非法选择,该选项设置失败。" << endl;}

  当我们在读取的时候:

switch(people.other_contact_case()){case PeopleInfo::OtherContactCase::kQq:cout << "qq号:" << people.qq() <<endl;break;case PeopleInfo::OtherContactCase::kWechat:cout << "微信号:" << people.wechat() << endl;break;}

map类型

map<key_type, value_type> map_field = N;
  跟c++的map差不多,用于key_type和value_type的关系映射。

  • key_type是除了float和bytes类型以外的任意标量类型。value_type可以是任意类型。
  • map不可以用repeated修饰。
  • map存入的元素是无序的。
//write:
for(int i = 1; ; i++){cout << "请输入备注" << i << "标题(只输入回车完成备注新增): ";string remark_key;getline(cin, remark_key);if(remark_key.empty()) break;cout << "请输入备注" << i << "内容:";string remark_value;getline(cin, remark_value);people_info_ptr->mutable_remark()->insert({remark_key, remark_value});}
// read:
if(people.remark_size()){cout << "备注信息:" << endl;}for(auto it = people.remark().cbegin(); it != people.remark().cend(); ++it){cout << "      " << it->first << ": " << it->second << endl;}

完整通讯录代码

.proto文件

syntax = "proto3";
package contacts;
import "google/protobuf/any.proto";message Address{string home_address = 1;string unit_address = 2;
}message PeopleInfo{string name = 1;uint32 age = 2;message Phone{string number = 1;enum PhoneType{MP = 0;TEL = 1;}PhoneType type = 2;}repeated Phone phone = 3;google.protobuf.Any data = 4;oneof other_contact{string qq = 5;string wechat = 6;}map<string, string> remark = 7;
}message Contacts{repeated PeopleInfo contacts = 1;
}

write文件

#include <iostream>
#include <fstream>
#include "contacts.pb.h"using namespace std;
using namespace contacts;
void AddPeopleInfo(PeopleInfo *people_info_ptr)
{cout << "---------------新增联系人-------------------" << endl;cout << "请输入联系人姓名:";string name;getline(cin, name);people_info_ptr->set_name(name);cout << "请输入联系人年龄:";int age;cin >> age;people_info_ptr->set_age(age);cin.ignore(256, '\n');for(int i = 1; ; i++){cout << "请输入联系人电话" << i << "(只输入回车完成电话新增): ";string number;getline(cin, number);if(number.empty()){break;}PeopleInfo_Phone *phone = people_info_ptr->add_phone();phone->set_number(number);cout << "选择此电话类型(1, 移动电话    2, 固定电话): ";int type;cin >> type;cin.ignore(256, '\n');switch(type){case 1:phone->set_type(PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP);break;case 2:phone->set_type(PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);break;default:cout << "非法选择,使用默认值" << endl;break;}}Address address;cout << "请输入联系人家庭地址:";string home_address;getline(cin, home_address);address.set_home_address(home_address);cout << "请输入联系人单位地址:";string unit_address;getline(cin, unit_address);address.set_unit_address(unit_address);google::protobuf::Any *data = people_info_ptr->mutable_data();data->PackFrom(address);cout << "选择一个其他联系方式(1,QQ号     2, 微信号): ";int other_contact;cin >> other_contact;cin.ignore(256, '\n');if(1 == other_contact){cout << "请输入QQ号:";string qq;getline(cin, qq);people_info_ptr->set_qq(qq);}else if(2 == other_contact){cout << "请输入微信号:" ;string wechat;getline(cin, wechat);people_info_ptr->set_wechat(wechat);}else{cout << "非法选择,该选项设置失败。" << endl;}for(int i = 1; ; i++){cout << "请输入备注" << i << "标题(只输入回车完成备注新增): ";string remark_key;getline(cin, remark_key);if(remark_key.empty()) break;cout << "请输入备注" << i << "内容:";string remark_value;getline(cin, remark_value);people_info_ptr->mutable_remark()->insert({remark_key, remark_value});}cout << "---------------添加联系人成功----------------" << endl;}
int main()
{Contacts contacts;fstream input("./contacts.bin", ios::in | ios::binary);if(!input){cerr << "contacts.bin file no found" << endl;return -1;}else if(!contacts.ParseFromIstream(&input)){cerr << "Failed to parse contacts" << endl;return -1;}AddPeopleInfo(contacts.add_contacts());fstream output("./contacts.bin", ios::out | ios::trunc | ios::binary);if(!contacts.SerializeToOstream(&output)){cerr << "Failed to write contacts." << endl;input.close();output.close();return -1;}input.close();output.close();return 0;
}

read文件

#include <iostream>
#include <fstream>
#include "contacts.pb.h"using namespace std;
using namespace contacts;void PrintContacts(const Contacts &contacts)
{for(int i = 0; i < contacts.contacts_size(); i++){const PeopleInfo &people = contacts.contacts(i);cout << "-----------------联系人" << i+1 << "---------------------" << endl;cout << "姓名:" << people.name() << endl;cout << "年龄:" << people.age() << endl;int j = 0; for(const PeopleInfo_Phone &phone : people.phone()){cout << "电话:" << j++ << phone.number() ;cout << "  (" << phone.PhoneType_Name(phone.type()) << ")" << endl;}if(people.has_data() && people.data().Is<Address>()){Address address;people.data().UnpackTo(&address);if(!address.home_address().empty()){cout << "家庭住址:" << address.home_address() << endl;}if(!address.unit_address().empty()){cout << "单位地址:" << address.unit_address() << endl;}}switch(people.other_contact_case()){case PeopleInfo::OtherContactCase::kQq:cout << "qq号:" << people.qq() <<endl;break;case PeopleInfo::OtherContactCase::kWechat:cout << "微信号:" << people.wechat() << endl;break;}if(people.remark_size()){cout << "备注信息:" << endl;}for(auto it = people.remark().cbegin(); it != people.remark().cend(); ++it){cout << "      " << it->first << ": " << it->second << endl;}}
}
int main()
{Contacts contacts;fstream input("contacts.bin", ios::in | ios::binary);if(!contacts.ParseFromIstream(&input)){cerr << "Failed to parse contacts." << endl;return -1;}PrintContacts(contacts);input.close();google::protobuf::ShutdownProtobufLibrary();return 0;
}

运行结果

./write
在这里插入图片描述

./read
在这里插入图片描述
在这里插入图片描述


       新人创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看。

相关文章:

【C++】protobuf的简单使用(通讯录例子)

protobuf的简单使用&#xff08;通讯录例子&#xff09; .proto文件的编写保留字段字段唯一编号protobuf的类型enum类型Any类型oneof类型map类型完整通讯录代码.proto文件write文件read文件运行结果 .proto文件的编写 syntax用于指定protobuf的语法&#xff1b;package当.prot…...

Apple 智能基础语言模型

Introducing Apple’s On-Device and Server Foundation Models technical details June 10, 2024 在2024年的全球开发者大会上&#xff0c;苹果推出了Apple Intelligence&#xff0c;这是一个深度集成到iOS 18、iPadOS 18和macOS Sequoia中的个人智能系统。Apple Intelligen…...

GreptimeDB融资数百万美元; Oracle提供免费长期MySQL; 谷歌大模型支持云数据库问题洞察

重要更新 1. 开源时序数据库 GreptimeDB宣布完成数百万美元的新一轮融资。GreptimeDB是一款Rust 语言编写的时序数据库&#xff0c;具有分布式&#xff0c;开源&#xff0c;云原生&#xff0c;兼容性强等特点&#xff0c;帮助企业实时读写、处理和分析时序数据的同时&#xff0…...

Java中的抽象类与接口

1. 抽象类 1.1 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c; 如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 比如&…...

云计算概念以及与云服务的区别

目录 1.云的概念 1.1 什么是云&#xff1f; 1.2 云计算的类型 1.3 云计算的服务模式 1.4 云计算的优势 2.云计算和云服务的区别 2.1 定义 2.2 范围 2.3 角色 2.5 举例 2.6使用者 3.总结 1.云的概念 1.1 什么是云&#xff1f; “云”在计算机科学和信息技术领域通常…...

Netty技术全解析:LengthFieldBaseFrameDecoder类深度解析

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…...

深入InnoDB核心:揭秘B+树在数据库索引中的高效应用

目录 一、索引页与数据行的紧密关联 &#xff08;一&#xff09;数据页的双向链表结构 &#xff08;二&#xff09;记录行的单向链表结构 二、未创建索引情况 &#xff08;一&#xff09;无索引下的单页查找过程 以主键为搜索条件 以非主键列为搜索条件 &#xff08;二…...

c++(面向对象的性质:抽象,封装,继承,多态)

ctrla全选&#xff0c;ctrli对齐 ctrl/ 一起注释 ctrlz 退回上一步 一些基础的内容&#xff1a; cout&#xff1a;输出流对象 cin&#xff1a;输入流对象 输入一个i和一个j&#xff0c;然后输出ij的和&#xff1a; 值不变的原因&#xff1a; 值传递&#xff0c;a和i是…...

java基础学习笔记1

Java编程规范 命名风格 1. 【强制】代码中的命名均不能以下划线或美元符号开始&#xff0c;也不能以下划线或美元符号结束。 反例&#xff1a;_name / __name / $name / name_ / name$ / name__ 2. 【强制】代码中的命名严禁使用拼音与英文混合的方式&#xff0c;更不允许直…...

[VBA]使用VBA在Excel中 操作 形状shape 对象

excel已关闭地图插件,对于想做 地图可视化 的,用形状来操作是一种办法,就是要自行找到合适的 地图形状,修改形状颜色等就可以用于 可视化展示不同省市销量、人口等数据。 引言 在Excel中,通过VBA(Visual Basic for Applications)可以极大地增强数据可视化和报告自动化…...

Apache POI 实现 Excel 表格下载

这里以苍穹外卖中数据导出功能为例&#xff0c;记录下 Apache POI 导出 Excel 表格的过程。 首先在 pom.xml 中导入相关依赖 <!-- poi 用于操作 excel 表格--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId&…...

大华嵌入式面试题大全及参考答案(2万字长文)

目录 在C语言中,static 关键字有哪些主要用途? static 修饰的全局变量与普通全局变量有什么区别? 为什么要在嵌入式系统中使用 static 修饰函数? 虚函数与纯虚函数了解么? strcpy 给你加结束符吗,还是要自己加? select 的作用是什么,它和 epoll 的区别? map 与…...

C语言——查漏补缺

前言 本篇博客主要记录一些C语言的遗漏点&#xff0c;完成查漏补缺的工作&#xff0c;如果读者感兴趣&#xff0c;可以看看下面的内容。都是一些小点&#xff0c;下面进入正文部分。 1. 字符汇聚 编写代码&#xff0c;演示多个字符从两端移动&#xff0c;向中间汇聚 #inclu…...

Python | Leetcode Python题解之第328题奇偶链表

题目&#xff1a; 题解&#xff1a; class Solution:def oddEvenList(self, head: ListNode) -> ListNode:if not head:return headevenHead head.nextodd, even head, evenHeadwhile even and even.next:odd.next even.nextodd odd.nexteven.next odd.nexteven even…...

吉瑞外卖笔记

1.项目整体搭建 这里用到的是springboot3mybatisplus 1.1数据库搭建 整体表搭建&#xff0c;这里我是直接用的老师给的数据库 1.2maven项目搭建 依赖 这两个jar包第一次用&#xff0c;记录一下 fastjson json处理&#xff0c;可将对象转化为json形式 可将对象中的属性…...

Perl套接字编程指南:构建网络通信应用

摘要 Perl是一种功能强大的脚本语言&#xff0c;广泛应用于系统管理、网络编程等多种场景。Perl的套接字编程能力允许开发者创建客户端和服务器端的网络应用。本文将详细介绍Perl中套接字的使用&#xff0c;包括基础概念、API的使用&#xff0c;以及构建简单客户端和服务器的示…...

达梦数据库(十) -------- mybatis-plus 整合达梦时,自动生成的 sql 语句报错

一丶【问题描述】&#xff1a; mybatis-plus 整合达梦时&#xff0c;应用系统项目的 sql 语句中包含数据库关键字&#xff0c;导致 mybatis-plus 自动生成的 sql 语句会报错&#xff0c;如下图所示&#xff1a; 二丶【问题解决】&#xff1a; 问题原因&#xff1a;mybatis-pl…...

停止项目大小调整,开始搜索层自动缩放!

作者&#xff1a;来自 Elastic Matteo Piergiovanni&#xff0c;John Verwolf 我们新的 serverless 产品的一个关键方面是允许用户部署和使用 Elastic&#xff0c;而无需管理底层项目节点。为了实现这一点&#xff0c;我们开发了搜索层自动扩展&#xff0c;这是一种根据我们将在…...

VScode的环境编译器选择

按快捷键 Ctrl Shift P 选择即可...

在Linux中通过docker安装和配置supervisor进程守护

先在Linux中安装docker&#xff0c;然后在docker中安装appnode&#xff0c;并进行docker网络端口映射。接着登录appnode面板安装supervisor。 supervisor用于守护进程&#xff0c;在进程意外终止后将其重启。 supervisor没有监听内部程序和自动重启的功能。 docker安装 第一…...

矽力杰 Silergy SY8521 降压稳压器 佰祥电子

100V母线辅助供电的“空间魔术”&#xff1a;SY8521全集成同步降压方案实战拆解在隔离型通信偏置电源、BMS高压从板以及汽车电子的48V/60V系统中&#xff0c;硬件团队在设计辅助供电轨时常常面临极其严苛的物理与电气双重挑战。系统母线在遭遇抛负载&#xff08;Load Dump&…...

实战踩坑:用Dify+DeepSeek对接MySQL,我遇到的5个典型错误和解决方案

实战踩坑&#xff1a;用DifyDeepSeek对接MySQL&#xff0c;我遇到的5个典型错误和解决方案 当Dify工作流遇上DeepSeek模型&#xff0c;再结合MySQL数据库查询&#xff0c;这个技术组合听起来很美好&#xff0c;但实际操作中却暗藏不少"坑"。作为已经踩过这些坑的开发…...

深刻理解智能指针特性

文章目录RAII思想unique_ptr 独占型shared_ptr 共享型weak_ptr 弱引用型总结RAII思想 RAII&#xff1a;资源获取即初始化—>把资源的生命周期绑定到栈上对象的生命周期&#xff0c;栈上对象离开作用域就自动销毁了 对象构造&#xff0c;拿到资源对象析构&#xff0c;释放资…...

告别知识管理焦虑!Karpathy 极简第二大脑实战指南(非常干货),帮你打造顶级思维外挂,建议收藏!

引言&#xff1a;知识管理的陷阱 你有没有这样的经历&#xff1f; • 收藏了 500 篇文章&#xff0c;却从来没看过第二遍• 买了 Notion/Obsidian 会员&#xff0c;花了两周搭建系统&#xff0c;三天后就放弃• 笔记越记越多&#xff0c;找的时候永远想不起来放在哪个文件夹•…...

ESP32-S3项目实战:从Github下载‘小智’代码到成功烧录的完整避坑记录

ESP32-S3项目实战&#xff1a;从Github下载‘小智’代码到成功烧录的完整避坑记录 在物联网开发领域&#xff0c;ESP32-S3凭借其出色的性能和丰富的外设接口&#xff0c;成为众多开发者的首选。本文将带你完整走一遍从Github获取"小智"开源项目到最终烧录运行的整个流…...

G-Helper终极指南:解锁华硕笔记本隐藏性能的5个秘密功能

G-Helper终极指南&#xff1a;解锁华硕笔记本隐藏性能的5个秘密功能 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, …...

如何用ULTIMATE ANIMATION COLLECTION打造3A级游戏动画效果?Unity 2022实战案例解析

如何用ULTIMATE ANIMATION COLLECTION打造3A级游戏动画效果&#xff1f;Unity 2022实战案例解析 在游戏开发领域&#xff0c;动画质量往往是区分平庸作品与精品的关键分水岭。当玩家控制角色挥剑时剑刃的轨迹是否流畅自然&#xff0c;角色与环境互动时是否呈现真实的物理反馈&a…...

保健及护理用家具市场:548.6亿元规模下的多维洞察

据恒州诚思调研统计&#xff0c;2025年全球保健及护理用家具收入规模约达466.7亿元&#xff0c;预计到2032年&#xff0c;这一数字将接近548.6亿元&#xff0c;2026 - 2032年的复合年增长率&#xff08;CAGR&#xff09;为2.5%。在医疗行业不断发展、人口结构持续变化的背景下&…...

leetcode 1624. 两个相同字符之间的最长子字符串-耗时100

Problem: 1624. 两个相同字符之间的最长子字符串 耗时100%&#xff0c;双指针&#xff0c;找到相同的以后直接break以及拿到最大值 Code class Solution { public:int maxLengthBetweenEqualCharacters(string s) {int n s.size(), mx -1;char ch;for(int i 0; i < n; i…...

AI创业,已经没有“出海”这个词了丨量子位沙龙

邓思邈 发自 凹非寺量子位 | 公众号 QbitAIAI创业&#xff0c;已经没有“出海”这个词了。如果你的计划还是“国内卷完再转战海外”&#xff0c;对不起&#xff0c;你可能已经提前出局。在这一波AI浪潮里&#xff0c;Day 0即全球化&#xff0c;早已是圈内默认的入场券。然而&am…...