protobuf C++
学习Caffe 无可避免的要学习和了解一下protobuf.
Caffe使用的是proto2版本。因此,我们下面下载proto2.
Caffe中使用的是(caffe.pb.h文件中)可以看到:
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3001000
即caffe.hp.h和caffe.hp.cc是使用protoc-3.1.0编译生成的。
注:这里总是给人误解,proto2的版本(proto2和proto3语法发生了某些变化),给出的protoc编译器却是protoc-3.1.0以3开头的。
protobuf 官方文档:
https://developers.google.com/protocol-buffers/docs/cpptutorial
- Define message formats in a .proto file.
- Use the protocol buffer compiler.
- Use the C++ protocol buffer API to write and read messages.
就像官网说的那样,仅需三个步骤就搞定:
- 定义一个.proto文件
- 使用protoc.exe编译.proto文件,生成.h和.cpp文件
- 使用C++protoAPI读写信息。
protobuf编译工具下载和安装:
旧版本下载地址:
http://repo1.maven.org/maven2/com/google/protobuf/protoc/
因为我们的Caffe代码包含了所需要的proto头文件和库文件,因此我们直接下载的可执行文件:
protoc-3.1.0-windows-x86_64.exe
使用下面的命令参数:
protoc-3.1.0-windows-x86_64.exe -I="E:/" --cpp_out="E:/" "E:/addressbook.proto"
格式为:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
然后在文E盘下就生成两个文件:addressbook.pb.cc 和 addressbook.pb.h
注:生成的两个文件依赖proto头文件和库文件,请确保自己电脑上面含有。
写消息:write_message.cpp
#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<string>
#include"addressbook.pb.h"
using namespace std;
//this funtion fill in a Person message based on user input
void PromptForAddress(tutorial::Person *person)
{
cout << "Enter person ID number:";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name:";
//使用指针的形式,设置成员的值,->优先级高于*,mutable_name返回string类型的指针,通过*进行解引用操作。
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none):";
string email;
getline(cin, email);
if (!email.empty())
{
//使用set函数设置成员的值
person->set_email(email);
}
while (true)
{
cout << "Enter a phone number(or leave blank to finish):";
string number;
getline(cin, number);
if (number.empty())
{
break;
}
//message中嵌套类型的使用:首先获取地址,然而对嵌套中的成员进行值的读写
tutorial::Person::PhoneNumber *phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile ,home,or work phone?";
string type;
getline(cin, type);
if (type == "mobile")
{
//message中枚举类型的使用
phone_number->set_type(tutorial::Person::MOBILE);
}
else if (type == "home")
{
phone_number->set_type(tutorial::Person::HOME);
}
else if (type == "work")
{
phone_number->set_type(tutorial::Person::WORK);
}
else
{
cout << "unknown phone type. using default." << endl;
}
}
}
/*main函数,从文件中读取完整的address book
用输入的方式来增加一个person,然后将其入同样的文件中。
*/
int main(int argc, char* argv[])
{
//检查连接的库的版本和编译的头文件的版本是否兼容
//GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2)
{
cerr << "usage: " << argv[0] << "ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
//读取现有的 address book
fstream input(argv[1], ios::in | ios::binary);
if (!input)
{
cout << argv[1] << "File not found. Creating a new file. " << endl;
}
else if (!address_book.ParseFromIstream(&input))
{
cerr << "Failed to parse address book. " << endl;
return -1;
}
}
//增加一个address
PromptForAddress(address_book.add_person());
{
//将新的address 写回到disk
//ios::trunc写入前先将内容全部清空
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output))
{
cerr << "Failed to write address book. " << endl;
return -1;
}
}
//可选的:删除libprotobuf分配的所有全局对象
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
读消息: read_message.cpp
#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<string>
#include"addressbook.pb.h"
using namespace std;
//迭代的访问addressbook中的所有人,并且打印输出他们的信息
void ListPeople(const tutorial::AddressBook& address_book)
{
for (int i = 0; i < address_book.person_size(); i++)
{
const tutorial::Person &person = address_book.person(i);
cout << "Person ID: " << person.id() << endl;
cout << "Name: " << person.name() << endl;
if (person.has_email())
{
cout << "E-mail address: " << person.email() << endl;
}
for (int j = 0; j < person.phones_size(); j++)
{
const tutorial::Person::PhoneNumber &phone_number = person.phones(j);
switch (phone_number.type())
{
case tutorial::Person::MOBILE:
cout << " Mobile phone #: ";
break;
case tutorial::Person::HOME:
cout << " Home phone #: ";
break;
case tutorial::Person::WORK:
cout << "Work phone #:";
break;
}
cout << phone_number.number() << endl;
}
}
}
//main 函数:从file 中读取完整的adress,并且打印出内部的所有信息
int main(int argc, char * argv[])
{
//验证连接库的版本和编译的头文件的版本是否一致
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2)
{
cerr << "usage: " << argv[0] << " address_book_file" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
//读取现有的address book
fstream input(argv[1], ios::in | ios::binary);
if (!address_book.ParseFromIstream(&input))
{
cerr << " failed to parse address book." << endl;
return -1;
}
}
ListPeople(address_book);
//可选的:删除libprotobuf分配的所有全局对象
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
caffe 中的protobuff
在caffe中,利用goolge的文本类型的类进行解析.prototxt文件,形如下:
tutorial::AddressBook address_book;
const char * filename = "addressbook.prototxt";
int fd = _open(filename, O_RDONLY);
FileInputStream * input = new FileInputStream(fd);
bool success = google::protobuf::TextFormat::Parse(input, &address_book);
解析后的内容全部存储在address_book对象中。
其中AddressBook就是上面通过编译器生成的类。
addressbook.prototxt文件的内容如下:
person
{
name : "zhangsan"
id: 2011010227
}
person
{
name: "lisi"
id: 2011010339
phones
{
number :"13026150789"
type: WORK
}
}
测试的主函数定义如下:
#include "stdafx.h"
#include<google/protobuf/io/zero_copy_stream_impl.h>
#include<google/protobuf/text_format.h>
#include"addressbook.pb.h"
#include<iostream>
#include<fstream>
using namespace std;
using google::protobuf::io::FileInputStream;
using google::protobuf::io::FileOutputStream;
#include<fcntl.h>
#include<io.h> //for windows
int main(void)
{
// protobuf 的使用
tutorial::AddressBook address_book;
const char * filename = "addressbook.prototxt";
int fd = _open(filename, O_RDONLY);
FileInputStream * input = new FileInputStream(fd);
bool success = google::protobuf::TextFormat::Parse(input, &address_book);
//输出
for (int i = 0; i < address_book.person_size(); i++)
{
cout << "Name :" << address_book.person(i).name();
cout << ", ID :" << address_book.person(i).id();
for (int j = 0; j < address_book.person(i).phones_size(); j++)
{
cout << ", PhoneNumber:" << address_book.person(i).phones(j).number();
}
cout << endl;
}
}
运行结果:
参考文献:
1 http://www.cnblogs.com/lidabo/p/3911456.html [protobuf c++入门]
2.http://blog.csdn.net/majianfei1023/article/details/45112415 [google protobuf学习笔记二:使用和原理]
3.http://blog.csdn.net/eclipser1987/article/details/8525383 [google protocol buffer (C++,Java序列化使用实例)]
4.http://blog.csdn.net/hailong0715/article/details/52057873 ProtoBuf安装和使用简介