找回密码
 立即注册
查看: 374|回复: 0

Protobuf读写Prototxt

[复制链接]
发表于 2022-1-29 20:28 | 显示全部楼层 |阅读模式
本文主要介绍了如何读取以及写入proto到bin文件以及读写prototxt相关的API
Bin二进制文件

Protobuf可以将程序运行中产生的数据保持到二进制文件中,与xml相比,其生成的文件更加小,读取速度更快,Protobuf工具中提供了其读写二进制API.
写bin文件API

通过查看google protocol开发API文档中的message.h头文件,message类中提供了写bin文件API,其函数原型为:
boolSerializeToOstream(std::ostream * output)
参数:
std::ostream * output:为文件输出数据流
message类为其定义的数据结构的一个基类,其提供了一列的操作,将其通用接口进行了统一封装.
google官方message API接口为:
https://developers.google.cn/protocol-buffers/docs/referenc/cpp/google.protobuf.message#Message.SerializeToOstream.details
除了上述按照输出流进行写bin文件之外,还提供了其他按照文件描述符进行操作,其他API还有:

返回值函数
boolSerializeToFileDescriptor(int file_descriptor)
boolSerializePartialToFileDescriptor(int file_descriptor)
boolSerializeToOstream(std::ostream * output)
boolSerializePartialToOstream(std::ostream * output)

用例一

相关用里proto数据结构,继续采用上节的Family数据结构,用例要求:向Family中添加两个成员并将最终结果写入到bin文件中,用例代码如下:
#include "family.pb.h"

#include <stdio.h>

#include <iostream>

#include <fstream>

#include <string>



using namespace std;



int main(){

  GOOGLE_PROTOBUF_VERIFY_VERSION;



  Family  family;

  Person* person;

const char * filename="test.db";



fstream output("test.db", ios::out | ios::binary);

if (!output)

  {

cout<<"output file : "<< filename << " is not found."<<endl;

  }



  person = family.add_person();

  person->set_age(25);

  person->set_name("John");



  person = family.add_person();

  person->set_age(40);

  person->set_name("Tony");



int size = family.person_size();



printf("size : %d \r\n", size);

for(int i = 0; i<size; i++)

  {

    Person psn=family.person(i);

cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;

  }



  family.SerializeToOstream(&output);



  google::protobuf::ShutdownProtobufLibrary();

return 0;

}

用例中将添加的两个成员,写入到test.db二进制文件中,运行用例:



生成的test.db文件如下:



打开db文件,其内容经过加密解压之后,为一堆二进制数据
读bin文件API

生成的bin文件不仅要求可以写文件,还要求可以读bin文件,并且能够将数据完全恢复出来,其相关API为

返回值函数
boolParseFromFileDescriptor(int file_descriptor)
boolParsePartialFromFileDescriptor(int file_descriptor)
boolParseFromIstream(std::istream * input)
boolParsePartialFromIstream(std::istream * input)

不仅支持数据流操作方式,还支持文件描述符参数
用例二

该用例继续延续写bin文件用例,将其上个用例生成的bin文件中的数据,读取出来:
#include "family.pb.h"

#include <stdio.h>

#include <iostream>

#include <fstream>

#include <string>



using namespace std;



int main(){

  GOOGLE_PROTOBUF_VERIFY_VERSION;



  Family  family;

  Person* person;

const char * filename="test.db";



fstream input("test.db", ios::in | ios::binary);

if (!input)

  {

cout<<"input file : "<< filename << " is not found."<<endl;

return -1;

  }



if (!family.ParseFromIstream(&input))

  {

cerr<<"Failed to parse address book."<<endl;

  }





int size = family.person_size();



printf("size : %d \r\n", size);

for(int i = 0; i<size; i++)

  {

    Person psn=family.person(i);

cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;

  }





  google::protobuf::ShutdownProtobufLibrary();

return 0;

}

运行结果:



Protobuf其bin文件的读写相对比较简单,API中将协议中的数据封装与解析,能够极大缩短了开发时间.
Prototxt文件

在caffe中可以看到其生成的网络拓扑结构以及参数,并不是bin文件二进制形式,而是prototxt形式.该形式是ProtoBuf数据保存的另外一种形势,主要是以txt形式.最主要的功能是可视化,在需要经常修改配置用于调参情况下,可以采用这样形式,该形式组成的生成格式是与proto中的数据结构相对应.
对Prototxt文件的读写APi是在text_format.h文件中:
https://developers.google.cn/protocol-buffers/docs/reference/cpp/google.protobuf.text_format
写Prototxt文件API

写Prototxt文件API列表如下:

返回值函数
boolPrint(const Message & message, io::ZeroCopyOutputStream * output)
boolPrintUnknownFields(const UnknownFieldSet & unknown_fields,io::ZeroCopyOutputStream * output)
boolPrintToString(const Message & message, string * output)
boolPrintUnknownFieldsToString(const UnknownFieldSet & unknown_fields, string * output)
boolPrintFieldValueToString(const Message & message, constFieldDescriptor * field, int index, string * output)

用例三

利用上述用例,将添加的两个成员写入到prototxt文件中,源码如下:

#include "family.pb.h"

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <iostream>

#include <fstream>

#include <string>

#include <fcntl.h>

#include <unistd.h>

#include <google/protobuf/io/coded_stream.h>

#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <google/protobuf/text_format.h>



using namespace std;

using google::protobuf::io::FileInputStream;

using google::protobuf::io::FileOutputStream;



int main(){

  GOOGLE_PROTOBUF_VERIFY_VERSION;



  Family  family;

  Person* person;

const char * filename="test.prototxt";



int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0777);

  FileOutputStream * output = new FileOutputStream(fd);



  person = family.add_person();

  person->set_age(25);

  person->set_name("John");



  person = family.add_person();

  person->set_age(40);

  person->set_name("Tony");



int size = family.person_size();



printf("size : %d \r\n", size);

for(int i = 0; i<size; i++)

  {

    Person psn=family.person(i);

cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;

  }



  google::protobuf::TextFormat::Print(family, output);

delete output;

  close(fd);



//google::protobuf::ShutdownProtobufLibrary();

return 0;

}

运行结果生成的prototxt文件内容如下:
person {

age: 25

  name: "John"

}

person {

age: 40

  name: "Tony"

}
其文件格式类似与python中的元组,其数据字段格式如下:
变量名字:变量值
查看proto文件

syntax = "proto2";



message Person {

  required int32 age = 1;

  required string name = 2;

}



message Family {

  repeated Person person = 1;

}
可以看到在prototxt中的字段是和proto中的字段是一一对应的,即proto文件定义数据结构格式,而prototxt定义具体的格式数据结构的每个字段的值,如果有多个相同的数据结构的值,则直接前面加上数据结构后面紧跟大括号即可
读Prototxt文件API

读取prototxt文件,并恢复文件里面的数据,相关API为:

返回值函数
boolParse(io::ZeroCopyInputStream * input, Message * output)
boolParseFromString(const string & input, Message * output)
boolMerge(io::ZeroCopyInputStream * input, Message * output)
boolMergeFromString(const string & input, Message * output)
boolParseFieldValueFromString(const string & input, constFieldDescriptor * field, Message * message)

用例四

将上述生成的text.prototxt文件,重新读取到内存中:

#include "family.pb.h"

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <iostream>

#include <fstream>

#include <string>

#include <fcntl.h>

#include <unistd.h>

#include <google/protobuf/io/coded_stream.h>

#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <google/protobuf/text_format.h>



using namespace std;

using google::protobuf::io::FileInputStream;

using google::protobuf::io::FileOutputStream;



int main(){

  GOOGLE_PROTOBUF_VERIFY_VERSION;



  Family  family;

  Person* person;

const char * filename="test.prototxt";



int fd = open(filename, O_RDONLY);

  FileInputStream * input = new FileInputStream(fd);



bool success = google::protobuf::TextFormat::Parse(input, &family);



int size = family.person_size();



printf("size : %d \r\n", size);

for(int i = 0; i<size; i++)

  {

    Person psn=family.person(i);

cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;

  }


delete input;

  close(fd);



//google::protobuf::ShutdownProtobufLibrary();

return 0;

}
运行结果:



能够成功将数据读取到内存中.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-5-31 09:05 , Processed in 0.207727 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表