protocol Buffer与JSON、XML
相同点:都是结构化数据处理工具。
差异点:
1、JSON和XML序列化是字符流,protocolBuffer序列化后不是可读的字符串,而是二进制流;
2、JSON和XML格式的数据信息都包含在了序列化之后的数据中,不需要任何其他信息就能还原序列化之后的数据。但使用Protocol Buffer时需要先定义数据的格式,还原一个序列化之后的数据需要使用到这个定义好的数据格式。
3、因为上述两个差别,Protocol Buffer序列化出来的数据要比XML格式的数据小3到10倍,解析时间快20到100倍。
Protocol Buffer安装
1、下载源代码:http://code.google.com/p/protobuf/downloads/list
2、解压编译安装,安装步骤如下所示:
tar -xzfprotobuf-2.1.0.tar.gz
cd protobuf-2.1.0
./configure --prefix=$INSTALL_DIR
make
make check
make install
Protocol Buffer的使用方式
1、编写protocol Buffer数据格式
以.proto文件存储。每个文件可以包含多个message。一个message代表一类结构化的数据。message里面定义了每一个属性的类型和名称。Protocol Buffer里属性的类型可以是像布尔型、字符串型、整数型、实数型、字符型这样的基本类型,也可以是另一个message。每一个属性需要编号,需要保证属性的序号不重叠且为正整数,通常从1开始递增,用来确定数据序列化顺序。每个属性还带有标志,共有三类标志:repeated\optional\required,分别表示属性是可重复的、可选的、必须的。可重复类型属性的取值可以是一个列表。另外,可以通过default设定属性的默认值。
示例:
message user{
required int32 id = 1;
optional string name = 2;
repeated string email = 3;
optional bool isChild = 4[default =false];
}
除此外,如果需要引用其他.proto文件中的message,可以使用import导入。
示例:
import"proto/outer_interface/facewash.proto";
注意:在最新的Protocol Buffer3中已经不再支持required类型。
2、编译.proto文件
写好 proto 文件之后就可以用 Protobuf 编译器将该文件编译成目标语言了。本例中我们将使用 C++。
假设您的 proto 文件存放在 $SRC_DIR 下面,您也想把生成的文件放在同一个目录下,则可以使用如下命令:
protoc -I=$SRC_DIR--cpp_out=$DST_DIR $SRC_DIR/example.proto
命令将生成两个文件:
example.pb.h ,定义了 C++ 类的头文件
example.pb.cc , C++ 类的实现文件
3、编写 writer 和 Reader
清单 2. Writer 的主要代码
#include "lm.helloworld.pb.h"
int main(void)
{
lm::helloworld msg1;
msg1.set_id(101);
msg1.set_str(“hello”);
//Write the new address book back to disk.
fstreamoutput("./log", ios::out | ios::trunc | ios::binary);
if(!msg1.SerializeToOstream(&output)) {
cerr << "Failed to write msg." << endl;
return -1;
}
return 0;
}
Msg1 是一个 helloworld 类的对象,set_id() 用来设置 id 的值。SerializeToOstream 将对象序列化后写入一个 fstream 流。
代码清单 3 列出了 reader 的主要代码。
清单 3. Reader
#include "lm.helloworld.pb.h"
…
voidListMsg(const lm::helloworld & msg) {
cout << msg.id() << endl;
cout << msg.str() << endl;
}
intmain(int argc, char* argv[]) {
lm::helloworld msg1;
{
fstream input("./log", ios::in | ios::binary);
if(!msg1.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
ListMsg(msg1);
…
}
同样,Reader 声明类 helloworld 的对象 msg1,然后利用 ParseFromIstream 从一个 fstream 流中读取信息并反序列化。此后,ListMsg 中采用 get 方法读取消息的内部信息,并进行打印输出操作。
文章内容并非完全原创。