protobuf中的message数据结构简明教程

参考资料:https://www.jianshu.com/p/b723053a86a6   // protobuf定义

https://zhuanlan.zhihu.com/p/25174418    // message结构描述

Protobuf是什么

Protobuf实际是一套类似Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。

message结构:

Protobuf通过定义message数据结构来进行使用。

  • 在一个proto文件中可以包含多个message定义,message之间可以互相引用,message还可以嵌套message和枚举类;
  • 一个message通常包含一至多个字段;
  • 每个字段包含以下几个部分:字段描述符(可选)、字段类型、字段名称和字段对应的Tag

字段描述符

字段描述符用于描述字段出现的频率,有以下两个可选值:

  • singular:表示出现0次或1次;如果没有声明描述符,默认为singular
  • repeated:表示出现0次或多次;

字段类型

  • 基本数据类型:包括doublefloatboolstringbytesint32int64uint32uint64sint32sint64fixed32fixed64sfixed32sfixed64
  • 引用其他message类型;
  • 枚举类型:对于枚举类型,protobuf有个约束:枚举的第一项对应的值必须为0

如下为一个message结构例子:

packeage MxTools;
message MxpiClass

{

    repeated MxpiMetaHeader headerVec = 1;

    int32 classId = 2;

    string className = 3;

    float confidence = 4;

}
message MxpiMetaHeader

{

    string parentName = 1;

    int32 memberId = 2;

    string dataSource = 3;

}
  • MxpiClass这个数据结构中,嵌套了另一个message类型(MxpiMetaHeader)
  • repeated声明该字段是可出现多次的。
  • 每个message里面的字段都有对应的Tag值,且Tag必须是唯一数字。Tag主要用于说明字段在二进制文件的对应关系,一旦指定字段为对应的Tag,不应该在后续进行变更;

如何对message数据结构进行数据操作

    下面,我们以MxpiClass为例子说明如何对message数据结构进行操作。

代码如下:

int main(int argc, char* argv[])

{

    MxpiClass  mxpiClass;
    // 对int类型字段赋值

    mxpiClass.set_classid(1);  //
    // 对string类型字段赋值

    mxpiClass.set_classname("MyMxpiClass");
    // 对repeated 类型字段赋值的方法.

    // 首先需要通过add_headervec()创建一个header_1,

    // 通过对header_1的赋值来实现赋值操作

    // 注意:此时的header_1是指针

    MxpiMetaHeader* header_1 = mxpiClass.add_headervec();

    header_1->set_datasource("myDataSource_1");

    header_1->set_memberid(1);

    // 对repeated类型数据的查看,查看第一个headerVec

    cout << mxpiClass.headervec(0).datasource()<<endl;

    cout << mxpiClass.headervec(0).memberid()<<endl;
    // 添加第二个headerVec

    MxpiMetaHeader* header_2 = mxpiClass.add_headervec();

    header_2->set_datasource("myDataSource_2");

    header_2->set_memberid(2);

    // 查看第二个headerVec

    cout << mxpiClass.headervec(1).datasource()<<endl;

    cout << mxpiClass.headervec(1).memberid()<<endl;

    // 输出mxpiClass的数据结构

    cout<< "MxpiClass {\n"<<mxpiClass.DebugString() <<"}"<<endl;

    return 0;

}

最后,采用DebugString()方法,显示mxpiClass的数据结构如下:

MxpiClass {

    headerVec {

    memberId: 1

    dataSource: "myDataSource_1"

    }

    headerVec {

    memberId: 2

    dataSource: "myDataSource_2"

    }

    classId: 1

    className: "MyMxpiClass"

}

嵌套message数据结构的数据操作:如果一个message结构嵌套了另一个message结构,如下所示:

message MxpiVision                         

{

    repeated MxpiMetaHeader headerVec = 1; 

    MxpiVisionInfo visionInfo = 2;

    MxpiVisionData visionData = 3;

}
message MxpiVisionData              

    uint64 dataPtr = 1;             

    int32 dataSize = 2;

    uint32 deviceId = 3;

    MxpiMemoryType memType = 4;

    uint64 freeFunc = 5;            

    bytes dataStr = 6;              

}
enum MxpiMemoryType {

    MXPI_MEMORY_HOST = 0;

    MXPI_MEMORY_DEVICE = 1;

    MXPI_MEMORY_DVPP = 2;

}

MxpiVision中嵌套了MxpiVsionData,如下代码示例如何对MxpiVsionData进行赋值。

int main(int argc, char* argv[])

{

    MxpiVision mxpiVsion;

    // 使用mutable方法新建一个MxpiVisionData数据类型,通过对Data赋值实现。

    MxpiVisionData* Data = mxpiVsion.mutable_visiondata();

    Data->set_dataptr(123456);

    Data->set_deviceid(1);

    // 对enum类型的字段赋值示例

    Data->set_memtype(MXPI_MEMORY_HOST);  

    return 0;

}

总结:

  1. 对于singular类的字段:
  • 基本数据类型的字段,通过“set_字段名()”方式进行赋值。
  • 对于嵌套的message字段,通过“mutable_字段名()”,新建一个该类数据结构,然后进行赋值。
  1. repeated字段:
  • 基本数据类型,通过“add_字段名()”,进行赋值,例如add_num(2)(numint型字段)
  • 对于嵌套的message字段,通过“add_字段名()”,添加一个该类的数据结构,然后进行赋值。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享