ProtoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,可用于表示通信协议和数据存储等各方面,与XML相比,ProtoBuF更小更快更简单。你可以用定义自己ProtoBuf的数据结构,用ProtoBuf编译器生成特定语言的源代码,(如C++,Java,Python等,目前 ProtoBuf对主流的编程语言都提供了支持)方便的进行序列化和反序列化。
protobuf是google旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现相同的协议格式即同一proto文件被编译成不同的语言版本,加入到各自的工程中去。这样不同语言就可以解析其他语言通过 protobuf序列化的数据。目前官网提供了C++,Python,JAVA,GO等语言的支持。
ProtoBuf 工作机制
- 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;
- }
- 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;
ProtoBuf的一个亮点是提供了向前和向后的兼容性,你可以再你定义的消息格式中增加字段或者删除字段,当消息由一个增加字段后的系统向一个老 版本系统发送消息时,老版本解析该消息格式后会直接忽略新增的字段,而当消息从老版本发向新版本时,新版本解析该消息时会将新增的字段设置为默认值,所以 你不需要担心在系统中增加消息字段后的兼容问题以及版本升级配套问题。
为什么不用XML
- <person>
- <name>John Doe</name>
- <email>jdoe@example.com</email>
- </person>
而在ProtoBuf中的定义是这样的:
- # Textual representation of a protocol buffer.
- # This is *not* the binary format used on the wire.
- person {
- name: "John Doe"
- email: "jdoe@example.com"
- }
- cout << "Name: " << person.name() << endl;
- cout << "E-mail: " << person.email() << endl;
而XML将会做如下动作:
- cout << "Name: "
- << person.getElementsByTagName("name")->item(0)->innerText()
- << endl;
- cout << "E-mail: "
- << person.getElementsByTagName("email")->item(0)->innerText()
- << endl;
然而,ProtoBuf与XML相比,有某些用途下并不是一个很好的解决方案,如ProtoBuf,并不适合用于给基本标签的文本文档建模,此外 XML是易读的,自描述的,而ProtoBuf的二进制文档并不是自描述的,除非拥有数据的源文件,否则你很难理解序列化后的文件中的内容,它是一个二进 制文件。
简单来说可按如下步骤使用ProtoBuf:
参考:
4. protobuf的使用