目录
- 什么是protobuffer?
- protobuffer是如何工作的?
- 为什么不用xml?
1.什么是protobuffer?
protobuffer是一种灵活,高效,自动化的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。您可以定义数据的结构化时间,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。您甚至可以更新数据结构,而不会破坏根据“旧”格式编译的已部署程序。
2.protobuffer是如何工作的?
您可以通过在.proto
文件中定义协议缓冲区消息类型来指定您希望如何构建序列化信息。每个协议缓冲区消息都是一个小的逻辑信息记录,包含一系列名称 - 值对。以下.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; }
如您所见,消息格式很简单 - 每种消息类型都有一个或多个唯一编号的字段,每个字段都有一个名称和一个值类型,其中值类型可以是数字(整数或浮点数),布尔值,字符串,字节,甚至(如上例所示)其他协议缓冲区消息类型,允许您分层次地构建数据。您可以指定可选字段,必填字段和重复字段。您可以.proto
在Protocol Buffer Language Guide中找到有关编写文件的更多信息。
一旦定义了消息,就可以在.proto
文件上运行应用程序语言的协议缓冲区编译器来生成数据访问类。这些为每个字段(如name()
和set_name()
)提供了简单的访问器,以及将整个结构序列化/解析为原始字节的方法 - 例如,如果您选择的语言是C ++,则在上面的示例中运行编译器将生成了Person类
。然后,您可以在应用程序中使用此类来填充,序列化和检索Person
协议缓冲区消息。然后你可以写一些这样的代码:
Person person; person.set_name("John Doe"); person.set_id(1234); person.set_email("[email protected]"); fstream output("myfile", ios::out | ios::binary); person.SerializeToOstream(&output);
然后可以这样读入消息
1 fstream input("myfile", ios::in | ios::binary); 2 Person person; 3 person.ParseFromIstream(&input); 4 cout << "Name: " << person.name() << endl; 5 cout << "E-mail: " << person.email() << endl;
您可以在消息格式中添加新字段,而不会破坏向后兼容性; 旧的二进制文件在解析时只是忽略新字段。因此,如果您的通信协议使用协议缓冲区作为其数据格式,则可以扩展协议,而无需担心破坏现有代码。
您将在API参考部分找到有关使用生成的协议缓冲区代码的完整参考,您可以在协议缓冲区编码中找到有关如何编码协议缓冲区消息的更多信息。
3.为什么不使用XML?
对于序列化结构化数据,protobuffer比XML具有许多优点。protobuffer:
- 更简单
- 比小3到10倍
- 快20到100倍
- 不那么暧昧
- 生成更易于以编程方式使用的数据访问类
例如,假设你想要定义一个拥有一个name和email的person。在XML中,您需要:
1 <person> 2 <name>John Doe</name> 3 <email>[email protected]</email> 4 </person>
而使用相应的protobuffer是:
1 # Textual representation of a protocol buffer. 2 # This is *not* the binary format used on the wire. 3 person { 4 name: "John Doe" 5 email: "[email protected]" 6 }
当此消息被编码为protobuffer二进制格式(上面的文本格式只是用于调试和编辑的方便的人类可读表示)时,它可能长达28个字节并且需要大约100-200纳秒来解析。如果删除空格,XML版本至少为69个字节,并且需要大约5,000-10,000纳秒才能解析。
此外操作protobuffer数据更容易:
1 cout << "Name: " << person.name() << endl; 2 cout << "E-mail: " << person.email() << endl;
如果你是用xml,可能是这个样子:
1 cout << "Name: " 2 << person.getElementsByTagName("name")->item(0)->innerText() 3 << endl; 4 cout << "E-mail: " 5 << person.getElementsByTagName("email")->item(0)->innerText() 6 << endl;
但是,protobuffer并不总是比XML更好的解决方案 - 例如,protobuffer不是使用标记(例如HTML)对基于文本的文档建模的好方法,因为您无法轻松地将结构与文本交错。此外,XML是人类可读的和人类可编辑的; XML在某种程度上也是自我描述的。只有拥有消息定义(.proto
文件)时,protobuffer才有意义。