本文主要会介绍怎么使用Google Protocol的Lib来序列化我们的数据,方法非常多种,本文仅仅介绍当中的三种。其它的方法读者能够通过自行研究摸索。但总的来说,序列化数据总的来说分为下面俩步:

     1)使用数据源填充数据结构,不管数据源来自文件还是内存还是标准输入

     2)利用Lib提供的序列化接口将数据结构序列化,然后存储在内存或者磁盘上

    

     一、填充数据结构 

     从数据源中获取数据。这儿的数据源可能来自磁盘上的一个文件或者内存中存储的一段数据或者来自标准输入的数据。我们须要做的就是,将AddressBook这个数据结构中的各个字段填充。本例中是通过AddressBook提供的add_person函数来获得一个Person的指针,从而对其进行填充,例如以下代码所看到的: 





    //地址簿数据定义

    AddressBook    addressBook;            

    

    //第一个联系人的数据定义与初始化

    Person    *personMe  = addressBook.add_person();

    personMe->set_id(1);

    personMe->set_name("royen");    

    personMe->set_email("zwg19891129@163.com");

    personMe->set_unsure("19bf173a0e87ab");

    

    //第二个联系人的数据定义与初始化

    Person  *personHim = addressBook.add_person();

    personHim->set_id(2);

    personHim->set_name("XXX");

    personHim->set_email("XXX@XXX.com");

    personHim->set_unsure("19bf173a0e87ab");

    

    //personMe的手机号码数据定义与初始化

    Person_PhoneNumber *phoneNumberMobile = personMe->add_phone();

    phoneNumberMobile->set_number("15996110120");

    phoneNumberMobile->set_type(Person_PhoneType_MOBILE);

        

    //personMe的座机号码数据定义与初始化

    Person_PhoneNumber *phoneNumberHome   = personMe->add_phone();

    phoneNumberHome->set_number("0256110120");

    phoneNumberHome->set_type(Person_PhoneType_HOME);





    //personHim的一个号码数据定义与初始化

    Person_PhoneNumber *phoneNumberHim      = personHim->add_phone();

    phoneNumberHim->set_number("15996111111");    

    phoneNumberHim->set_type(Person_PhoneType_HOME);









         非常easy看出,上述代码即在地址簿中加入了俩个联系人。然后又分别填充各个联系人的数据信息,通过上述代码一个地址簿的数据便准备好了。

二、序列化数据 

        事实上通过看编译器生成的AddressBook这个类所提供的方法名,既能够大致知道有哪些序列化的方式。例如以下所看到的:

         

        从上图能够看出。可利用序列化的方法非常多,本文中主要使用SerializeToString、SerializeToCodedStream以及SerializeToOstream来完毕序列化。 

        以下就分别就这几种方式来介绍下:

        1) SerializeToCodedStream方式

        首先能够知道该函数的原型是bool SerializeToCodedStream(std::ostream *),所以使用该函数须要结合C++的fstream流。代码例如以下:         





    //方法一: 使用SerializePartialToOstream来序列化,注意ios::binary以二进制流写入文件

    fstream  fserial("addressbook.data",ios::out | ios::trunc | ios::binary);    

    if (!addressBook.SerializePartialToOstream(&fserial))

    {

       cerr<<"Failed to serial address book data!\n";

       return;

    }

    cout<<"Serial address book data successfully!\n";

    fserial.close();

    fserial.clear();









          能够看出,採用这样的方法相当的便捷,并且也非常简洁,但有个缺点就是输出到文件的编码格式不好控制,所以能够使用以下介绍的这样的方法。

2)SerializeToString方式

       函数原型为bool SerializeToString(std::string* output) ,所以能够讲填充在数据结构AddressBook中的数据取出存到一个string对象中,然后再以二进制流的方式将其写入到磁盘文件里。代码例如以下:               





    FILE    *g_AddressBook = fopen("addressbook.data","wb,ccs = UNICODE");

    if( NULL == g_AddressBook )

    {

        cerr<<"Create addressbook.data failed!\n";

        return ;

    }





    string    serialStream = "";

    if( !addressBook.SerializePartialToString(&serialStream) )

    {

        cerr<<"Failed to serial addressbook data!\n";

        return;

    }





    fwrite( serialStream.c_str(),sizeof(char),addressBook.ByteSize(),g_AddressBook);

    cout<<"serial address successfully!\n";

    if( g_AddressBook )

    {

        fclose(g_AddressBook);

        g_AddressBook = NULL;

    } 









       上述代码略微繁琐了点。可是也是一种序列化的方式。通过结合使用C库中的文件操作函数,能够更方便的定制输出文件。

  

       3)SerializeToCodedStream方式

       该方式主要指用到的google buffer的库中提供的一组数据流操作对象。在使用这些对象之前须要引入一些头文件。例如以下所看到的:       

   #include <google/protobuf/io/zero_copy_stream_impl.h>

   #include <google/protobuf/io/zero_copy_stream.h>

   #include <google/protobuf/io/coded_stream.h> 

   using namespace::google::protobuf::io;





       该方式也结合C库的open与write函数,序列化部分的代码例如以下:               





    int fd  = _open("addressbook.data", _O_WRONLY |_O_CREAT| _O_BINARY, _S_IREAD|_S_IWRITE);    

    if( -1 == fd )

    {

        cerr<<"Create addressbook.data failed!\n";

        return ;

    }

    char tmpArr[MAX_SIZE];

    memset(tmpArr,0,sizeof(tmpArr));

    ZeroCopyOutputStream *raw_output = new ArrayOutputStream(tmpArr,addressBook.ByteSize()+1);    

    CodedOutputStream* coded_output = new CodedOutputStream(raw_output);    

    if( !addressBook.SerializeToCodedStream( coded_output ))

    {

        cerr<<"Fail to serial addressbook data!\n";

        return;

    }    

    _write(fd,tmpArr,addressBook.ByteSize()+1);

    cout<<"serial address successfully!\n";

    delete coded_output;

    delete raw_output;        

    close(fd);    





        本文临时介绍这三种序列化话方式,还有像SerializeToArray以及SerializeToFileDescriptor等方式都应该比較类似。所以感兴趣的朋友能够自己动手试试。

google protocol buffer的原理和使用(二)的更多相关文章

  1. google protocol buffer的原理和使用(一)

    一.简单的介绍      Protocol buffers是一个用来序列化结构化数据的技术,支持多种语言诸如C++.Java以及Python语言.能够使用该技术来持久化数据或者序列化成网络传输的数据. ...

  2. google protocol buffer的原理和使用(三)

    介绍下怎么反序列化GoogleBuffer数据.并在最后提供本系列文章中所用到的代码整理供下载. 上一篇文章介绍了如何将数据序列化到了addressbook.data中.那么对于接受方而言该怎么解析出 ...

  3. google protocol buffer的原理和使用(四)

    有个电子商务的系统(如果用C++实现).当中的模块A须要发送大量的订单信息给模块B.通讯的方式使用socket. 如果订单包含例如以下属性: ----------------------------- ...

  4. Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  5. 转Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  6. Google Protocol Buffer 的使用(二)

    一.protobuf应用场景 protobuf 在Java中的应用场景可以是序列化和反序列化,流可以通过文件或者通过网络TCP/UDP等方式传输.新建一个.proto文件 syntax = " ...

  7. Google Protocol Buffer 的使用和原理[转]

    本文转自: http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/ Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构 ...

  8. Google Protocol Buffer 的使用和原理(无论对存储还是数据交换,都是个挺有用的东西,有9张图做说明,十分清楚)

    感觉Google Protocol Buffer无论对存储还是数据交换,都是个挺有用的东西,这里记录下,以后应该用得着.下文转自: http://www.ibm.com/developerworks/ ...

  9. (转)Google Protocol Buffer 的使用和原理

    转自:https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html   简介 什么是 Google Protocol Buffer? ...

随机推荐

  1. (转)python的range()函数用法

    使用python的人都知道range()函数很方便,今天再用到他的时候发现了很多以前看到过但是忘记的细节.这里记录一下range(),复习下list的slide,最后分析一个好玩儿的冒泡程序. 转自: ...

  2. js javascript 原型链详解

    看了许多大神的博文,才少许明白了js 中原型链的概念,下面给大家浅谈一下,顺便也是为了巩固自己 首先看原型链之前先来了解一下new关键字的作用,在许多高级语言中,new是必不可少的关键字,其作用是为了 ...

  3. Java 集合Collection——初学者参考,高手慎入(未完待续)

    1.集合简介和例子 Collection,集合.和数学定义中的集合类似,把很多元素放在一个容器中,方便我们存放结果/查找等操作. Collection集合实际上是很多形式集合的一个抽象. 例如十九大就 ...

  4. JXOI2017-2018 解题报告

    链接:JXOI2017-2018 解题报告 代码预览:Github

  5. 理解事件(Event)

    Overview 在前几章,我们已经对委托有了一个完整的了解了,本章将会对事件进行一下介绍: 相对于委托,事件再是我们更加频繁的接触的,比如 鼠标的click 事件,键盘的 keydown 事件等等. ...

  6. 复杂密码生成工具apg

    复杂密码生成工具apg   密码是身份认证的重要方式.由于密码爆破方式的存在,弱密码非常不安全.为了构建复杂密码,Kali Linux预置了一个复杂密码生成工具apg.该工具可以提供可读密码和随机字符 ...

  7. JavaSE基础之封装

    JavaSE基础之封装 一.Java中的封装 1.字面意思: 包装: 2.专业含义: 面向对象的三大特征之一: 指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所 ...

  8. [BZOJ1758][WC2010]重建计划(点分治+单调队列)

    点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...

  9. hihocoder 1866 XOR

    题面在这里 拆位分析一下就OK啦 /* y + (y xor x) */ #include<bits/stdc++.h> #define ll long long using namesp ...

  10. ROS知识(14)----局部避障的动态窗口算法(DWA)及其调试的方法

    Dynamic Window Approach(DWA)是重要的局部轨迹规划算法,ROS中使用了DWA算法获得了很好的局部路径规划的效果.具体的教程可参考官方的导航调试资料Navigation Tun ...