欢迎使用protobuf的开发人员文档 - 一种与语言无关,平台无关,可扩展的序列化结构化数据的方法,用于通信协议,数据存储等。
本文档面向希望在其应用程序中使用protobuf的Java,C ++或Python开发人员。本概述介绍了protobuf,并告诉您需要做什么才能开始 - 然后您可以继续学习本 教程 或深入研究 protobuf编码。 还为所有三种语言提供了API 参考文档,以及 用于编写.proto 文件的语言 和 样式指南 。
什么是protobuf?
protobuf是一种灵活,高效,自动化的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。您可以定义数据的结构化时间,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。您甚至可以更新数据结构,而不会破坏根据“旧”格式编译的已部署程序。
他们是如何工作的?
您可以通过在.proto 文件中定义protobuf消息类型来指定您希望如何构建序列化信息 。每个protobuf消息都是一个小的逻辑信息记录,包含一系列名称 - 值对。这是一个.proto 文件的一个非常基本的例子, 它定义了一个包含有关人员信息的消息:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
如您所见,消息格式很简单 - 每种消息类型都有一个或多个唯一编号的字段,每个字段都有一个名称和一个值类型,其中值类型可以是数字(整数或浮点数),布尔值,字符串,原始字节,甚至(如上例所示)其他protobuf消息类型,允许您分层次地构建数据。您可以指定可选字段, 必填字段和重复字段。您可以 在Protocol Buffer Language Guide中找到有关编写.proto 文件的 更多信息 。
一旦定义了消息,就可以在.proto 文件上运行应用程序语言的protobuf编译器 来生成数据访问类。这些为每个字段提供了简单的访问器(如 name() 和 set_name()),以及将整个结构序列化/解析为原始字节的方法 - 例如,如果您选择的语言是C ++,则运行编译器上面的例子将生成一个名为Person 的类 。然后,您可以在应用程序中使用此类来填充,序列化和检索 Person protobuf消息。然后你可以写一些这样的代码:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
为什么不使用XML?
对于序列化结构化数据,protobuf比XML具有许多优点。protobuf:
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
name: "John Doe"
email: "jdoe@example.com"
}
当此消息被编码为protobuf 二进制格式 (上面的文本格式只是用于调试和编辑的方便的人类可读表示)时,它可能长达28个字节并且需要大约100-200纳秒来解析。如果删除空格,XML版本至少为69个字节,并且需要大约5,000-10,000纳秒才能解析。
此外,操作protobuf更容易:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
cout << "Name: "
<< person.getElementsByTagName("name")->item(0)->innerText()
<< endl;
cout << "E-mail: "
<< person.getElementsByTagName("email")->item(0)->innerText()
<< endl;