|
本文主要介绍了如何读取以及写入proto到bin文件以及读写prototxt相关的API
Bin二进制文件
Protobuf可以将程序运行中产生的数据保持到二进制文件中,与xml相比,其生成的文件更加小,读取速度更快,Protobuf工具中提供了其读写二进制API.
写bin文件API
通过查看google protocol开发API文档中的message.h头文件,message类中提供了写bin文件API,其函数原型为:
bool | SerializeToOstream(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还有:
返回值 | 函数 | bool | SerializeToFileDescriptor(int file_descriptor) | bool | SerializePartialToFileDescriptor(int file_descriptor) | bool | SerializeToOstream(std::ostream * output) | bool | SerializePartialToOstream(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=&#34;test.db&#34;;
fstream output(&#34;test.db&#34;, ios::out | ios::binary);
if (!output)
{
cout<<&#34;output file : &#34;<< filename << &#34; is not found.&#34;<<endl;
}
person = family.add_person();
person->set_age(25);
person->set_name(&#34;John&#34;);
person = family.add_person();
person->set_age(40);
person->set_name(&#34;Tony&#34;);
int size = family.person_size();
printf(&#34;size : %d \r\n&#34;, size);
for(int i = 0; i<size; i++)
{
Person psn=family.person(i);
cout <<&#34;Name :&#34;<<psn.name()<<&#34;, age: &#34;<<psn.age()<<endl;
}
family.SerializeToOstream(&output);
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
用例中将添加的两个成员,写入到test.db二进制文件中,运行用例:
生成的test.db文件如下:
打开db文件,其内容经过加密解压之后,为一堆二进制数据
读bin文件API
生成的bin文件不仅要求可以写文件,还要求可以读bin文件,并且能够将数据完全恢复出来,其相关API为
返回值 | 函数 | bool | ParseFromFileDescriptor(int file_descriptor) | bool | ParsePartialFromFileDescriptor(int file_descriptor) | bool | ParseFromIstream(std::istream * input) | bool | ParsePartialFromIstream(std::istream * input) |
不仅支持数据流操作方式,还支持文件描述符参数
用例二
该用例继续延续写bin文件用例,将其上个用例生成的bin文件中的数据,读取出来:
#include &#34;family.pb.h&#34;
#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=&#34;test.db&#34;;
fstream input(&#34;test.db&#34;, ios::in | ios::binary);
if (!input)
{
cout<<&#34;input file : &#34;<< filename << &#34; is not found.&#34;<<endl;
return -1;
}
if (!family.ParseFromIstream(&input))
{
cerr<<&#34;Failed to parse address book.&#34;<<endl;
}
int size = family.person_size();
printf(&#34;size : %d \r\n&#34;, size);
for(int i = 0; i<size; i++)
{
Person psn=family.person(i);
cout <<&#34;Name :&#34;<<psn.name()<<&#34;, age: &#34;<<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列表如下:
返回值 | 函数 | bool | Print(const Message & message, io::ZeroCopyOutputStream * output) | bool | PrintUnknownFields(const UnknownFieldSet & unknown_fields,io::ZeroCopyOutputStream * output) | bool | PrintToString(const Message & message, string * output) | bool | PrintUnknownFieldsToString(const UnknownFieldSet & unknown_fields, string * output) | bool | PrintFieldValueToString(const Message & message, constFieldDescriptor * field, int index, string * output) |
用例三
利用上述用例,将添加的两个成员写入到prototxt文件中,源码如下:
#include &#34;family.pb.h&#34;
#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=&#34;test.prototxt&#34;;
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(&#34;John&#34;);
person = family.add_person();
person->set_age(40);
person->set_name(&#34;Tony&#34;);
int size = family.person_size();
printf(&#34;size : %d \r\n&#34;, size);
for(int i = 0; i<size; i++)
{
Person psn=family.person(i);
cout <<&#34;Name :&#34;<<psn.name()<<&#34;, age: &#34;<<psn.age()<<endl;
}
google::protobuf::TextFormat::Print(family, output);
delete output;
close(fd);
//google::protobuf::ShutdownProtobufLibrary();
return 0;
}
运行结果生成的prototxt文件内容如下:
person {
age: 25
name: &#34;John&#34;
}
person {
age: 40
name: &#34;Tony&#34;
}
其文件格式类似与python中的元组,其数据字段格式如下:
变量名字:变量值 查看proto文件
syntax = &#34;proto2&#34;;
message Person {
required int32 age = 1;
required string name = 2;
}
message Family {
repeated Person person = 1;
}
可以看到在prototxt中的字段是和proto中的字段是一一对应的,即proto文件定义数据结构格式,而prototxt定义具体的格式数据结构的每个字段的值,如果有多个相同的数据结构的值,则直接前面加上数据结构后面紧跟大括号即可
读Prototxt文件API
读取prototxt文件,并恢复文件里面的数据,相关API为:
返回值 | 函数 | bool | Parse(io::ZeroCopyInputStream * input, Message * output) | bool | ParseFromString(const string & input, Message * output) | bool | Merge(io::ZeroCopyInputStream * input, Message * output) | bool | MergeFromString(const string & input, Message * output) | bool | ParseFieldValueFromString(const string & input, constFieldDescriptor * field, Message * message) |
用例四
将上述生成的text.prototxt文件,重新读取到内存中:
#include &#34;family.pb.h&#34;
#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=&#34;test.prototxt&#34;;
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(&#34;size : %d \r\n&#34;, size);
for(int i = 0; i<size; i++)
{
Person psn=family.person(i);
cout <<&#34;Name :&#34;<<psn.name()<<&#34;, age: &#34;<<psn.age()<<endl;
}
delete input;
close(fd);
//google::protobuf::ShutdownProtobufLibrary();
return 0;
}
运行结果:
能够成功将数据读取到内存中. |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|