ProtoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,可用于表示通信协议和数据存储等各方面,与XML相比,ProtoBuF更小更快更简单。你可以用定义自己ProtoBuf的数据结构,用ProtoBuf编译器生成特定语言的源代码,(如C++,Java,Python等,目前 ProtoBuf对主流的编程语言都提供了支持)方便的进行序列化和反序列化。

protobuf是google旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现相同的协议格式即同一proto文件被编译成不同的语言版本,加入到各自的工程中去。这样不同语言就可以解析其他语言通过 protobuf序列化的数据。目前官网提供了C++,Python,JAVA,GO等语言的支持。

ProtoBuf 工作机制

在一个后缀名为.pro的文件中定义你所需的任何需要序列化和反序列的结构,类似于中我们C/C++语言中的结构体定义,也类似于JSON类定义,ProtoBuf文件的每一个属性都是一个键值对,引用谷歌官方的例子说明,一个包含Person信息的.pro文件。
  1. message Person {
  2. required string name = 1;
  3. required int32 id = 2;
  4. optional string email = 3;
  5. enum PhoneType {
  6. MOBILE = 0;
  7. HOME = 1;
  8. WORK = 2;
  9. }
  10. message PhoneNumber {
  11. required string number = 1;
  12. optional PhoneType type = 2 [default = HOME];
  13. }
  14. repeated PhoneNumber phone = 4;
  15. }

.pro 文件的每一个属性都是一个包含类型和名称的对,protobuf的类型可以是string,int,bool,或者是其他ProtoBuf源文件中定位的 类型等。还开元指定该属性的一些特殊字段,比l如optional表示该属性是可选的,required表示该属性是必须的,repeated表示该属性 是一个list的集合(不知道用list类似形容是否合适,就差不多意思吧,包含1个或多个元素),包含了若干个相同类型的值,不过在protoBuf 3中,optional和required都不需要的了,如果配了两个,protoBuf 编译器还会报错,但是repeated的还是保留的,用来说明该字段是一个list。

.protoBuf定义完以后,就可以使用ProtoBuf编 译器进行编译,编译时需要指定你需要生成的代码的语言类型。.pro文件编译成功后会生成*.pro.pb.hh 和*.pro.pb.cc两个文件,*和.pro源文件名称相同。在生成的文件中会生成一个你定义的消息类型的的类以及读取和设置该消息类型各个属性的 set和Get方法等,比如上例中会生成一个Person类,和name(),set_name()这样的成员方法,以及序列化和反序列的方法,你可以用 这些方法方便的读取和设置相应的属性,以及序列化和反序列化方法。
你可以像如下的方式序列化
  1. Person person;
  2. person.set_name("John Doe");
  3. person.set_id(1234);
  4. person.set_email("jdoe@example.com");
  5. fstream output("myfile", ios::out | ios::binary);
  6. 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;

ProtoBuf的一个亮点是提供了向前和向后的兼容性,你可以再你定义的消息格式中增加字段或者删除字段,当消息由一个增加字段后的系统向一个老
版本系统发送消息时,老版本解析该消息格式后会直接忽略新增的字段,而当消息从老版本发向新版本时,新版本解析该消息时会将新增的字段设置为默认值,所以
你不需要担心在系统中增加消息字段后的兼容问题以及版本升级配套问题。

为什么不用XML

在序列化和反序列化结构化数据时,ProtoBuf拥有XML很多无可比拟的优势:
1、它比XML更为简单。这点显而易见
2、存储同样的数据比XML小3到10倍
3、运行速度比XML快20到100倍
4、更小的二义性
5、直接利用类和成员方法序列化反序列化数据更有利于编程。
 
比如你需要定义个结构化数据Person,包含了name和email属性,在XML中你会这样定义:
  1. <person>
  2. <name>John Doe</name>
  3. <email>jdoe@example.com</email>
  4. </person>
而在ProtoBuf中的定义是这样的:
  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: "jdoe@example.com"
  6. }
如果将上述的ProtoBuf文件序列化,它仅仅占据28个字节的空间,解析该文件也仅仅需要100到200纳秒,而相同的XML文件至少需要
69个字节存储数据(除去空白),解析该XML文件至少需要10000纳秒,而在对数据的操作方面ProtoBuf的操作也更加简单:
  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;

然而,ProtoBuf与XML相比,有某些用途下并不是一个很好的解决方案,如ProtoBuf,并不适合用于给基本标签的文本文档建模,此外
XML是易读的,自描述的,而ProtoBuf的二进制文档并不是自描述的,除非拥有数据的源文件,否则你很难理解序列化后的文件中的内容,它是一个二进
制文件。

简单来说可按如下步骤使用ProtoBuf:

1. 定义你自己的数据结构格式(.pro)源文件。
2. 利用protoBuf提供的编译器编译源文件。
3. 使用ProtoBuf C++的API 读写消息。 

参考:

1. 数据交换利器 Protobuf 技术浅析

2. 谷歌 Google ProtoBuf用法实例

3. Google ProtoBuf简介

4. protobuf的使用

protobuf--数据序列化及反序列化的更多相关文章

  1. XPatchLib 对象增量数据序列化及反序列化器 For .Net

    在日常的软件开发和使用过程中,我们发现同一套系统的同一配置项在不同的客户环境中是存在各种各样的差异的.在差异较为分散时,如何较好的管理这些差异,使得维护过程能够更加安全和快速,一直在这样那样的困扰着开 ...

  2. [Go] 使用protobuf进行序列化和反序列化

    先定义消息类型 orders.proto syntax = "proto2"; package message; message Orders { required int32 o ...

  3. c++/qt的数据序列化和反序列化

    序列化以及反序列化的实现 struct Body { double weight; double height; }; //结构体 struct People { int age; Body dBod ...

  4. unity探索者之protobuf的序列化和反序列化导致unity崩溃的问题研究

    版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/7574569.html 这两天博主在接微信支付SDK的时候碰到一个非常恶心又诡异的问 ...

  5. php函数serialize()与unserialize() 数据序列化与反序列化

    php函数serialize()与unserialize()说明及案例.想要将已序列化的字符串变回 PHP 的值,可使用unserialize().serialize()可处理除了resource之外 ...

  6. 数据序列化之protobuf

    数据序列化之protobuf 很多时候需要将一些数据打包,就是把这些数据搞在一起,方便处理.最常见的情况就是把需要传输的数据,当然数据不止一条,打包成一个消息,然后发送出去,接收端再以一定的规则接收并 ...

  7. 详解电子表格中的json数据:序列化与反序列化

    从XML到JSON 当下应用开发常见的B/S架构之下,我们会遇到很多需要进行前后端数据传输的场景.而在这个传输的过程中,数据通过何种格式传输.方式是否迅速便捷.书写方式是否简单易学,都成为了程序员在开 ...

  8. Json序列化与反序列化

    参考:http://www.cnblogs.com/caofangsheng/p/5687994.html#commentform 下载链接:http://download.csdn.net/deta ...

  9. Python库:序列化和反序列化模块pickle介绍

    1 前言 在“通过简单示例来理解什么是机器学习”这篇文章里提到了pickle库的使用,本文来做进一步的阐述. 通过简单示例来理解什么是机器学习 pickle是python语言的一个标准模块,安装pyt ...

  10. 数据序列化导读(1)[JSON]

    所谓数据序列化(Data Serialization), 就是将某个对象的状态信息转换为可以存储或传输的形式的过程. 那么,为什么要进行序列化? 首先,为了方便数据存储: 其次,为了方便数据传递. 在 ...

随机推荐

  1. LinkedHashMap插入无序且链式操作

    Iterator<Entry<Integer, Integer>> ite=lhmap.entrySet().iterator(); ite.next(); ite.remov ...

  2. linux显示桌面快捷键设置

    2013-01-06 10:31:52    Ubuntu显示桌面Indicator  IN: LINUX :-) HOT: 1,246 ℃  18十2011   www.2cto.com   大家一 ...

  3. HDUOJ---1233还是畅通工程

    还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  4. set 容器 的全解(转)

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构 ...

  5. 使用JavaStcript对数组元素去重的方法

    在做javascript开发的时候,经常会遇到数组元素重复的问题,而javascript Array又没有直接提供方法解决此问题,还需要自己去实现. 方案一: 思路: 1.构建一个新的数组存放结果: ...

  6. gVim 中文内容显示为乱码的解决办法

    http://blog.csdn.net/sunmanzth/article/details/6143600打开vimrc文件,在vim的安装目录下可以找到该文件,或在windows下是在vim/gv ...

  7. 解决 无法将文件" "复制到“bin\*.*”。对路径“bin\*.*”的访问被拒绝。

    关于这个问题今天碰到了, 我的解决办法很简单: 删除bin目录下的所有文件,然后重新生成,就不报错了.

  8. 简述C#中IO的应用 RabbitMQ安装笔记 一次线上问题引发的对于C#中相等判断的思考 ef和mysql使用(一) ASP.NET/MVC/Core的HTTP请求流程

    简述C#中IO的应用   在.NET Framework 中. System.IO 命名空间主要包含基于文件(和基于内存)的输入输出(I/O)服务的相关基础类库.和其他命名空间一样. System.I ...

  9. OpenCV245之SURF源代码分析

    一.fastHessianDetector函数分析 (1)參数 const Mat& sum                积分图片 const Mat& mask_sum vecto ...

  10. Python rstrip() 方法

    描述 Python rstrip() 方法用于删除字符串尾部指定的字符,默认字符为所有空字符,包括空格.换行(\n).制表符(\t)等. 语法 rstrip() 方法语法: S.rstrip([cha ...