最常用的两种C++序列化方案的使用心得(protobuf和boost serialization)

From: http://www.cnblogs.com/lanxuezaipiao/p/3703988.html

 

导读

1. 什么是序列化?

2. 为什么要序列化?好处在哪里?

3. C++对象序列化的四种方法

4. 最常用的两种序列化方案使用心得


正文

1. 什么是序列化?

程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将 程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)。

简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻 松地存储和传输数据。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。

 

总结

序列化:将对象变成字节流的形式传出去。

反序列化:从字节流恢复成原来的对象。


2. 为什么要序列化?好处在哪里?

简单来说,对象序列化通常用于两个目的:  

(1) 将对象存储于硬盘上  ,便于以后反序列化使用

(2)在网络上传送对象的字节序列


对象序列化的好处在哪里?网络传输方面的便捷性、灵活性就不说了,这里举个我们经常可能发生的需求:你 有一个数据结构,里面存储的数据是经过很多其它数据通过非常复杂的算法生成的,由于数据量很大,算法又复杂,因此生成该数据结构所用数据的时间可能要很久 (也许几个小时,甚至几天),生成该数据结构后又要用作其它的计算,那么你在调试阶段,每次运行个程序,就光生成数据结构就要花上这么长的时间,无疑代价 是非常大的。如果你确定生成数据结构的算法不会变或不常变,那么就可以通过序列化技术生成数据结构数据存储到磁盘上,下次重新运行程序时只需要从磁盘上读 取该对象数据即可,所花费时间也就读一个文件的时间,可想而知是多么的快,节省了我们的开发时间。


3. C++对象序列化的四种方法

将C++对象进行序列化的方法一般有四种,下面分别介绍:


3.1 Google Protocol Buffers(protobuf)

Google Protocol Buffers (GPB)是Google内部使用的数据编码方式,旨在用来代替XML进行数据交换。可用于数据序列化与反序列化。主要特性有:

  • 高效
  • 语言中立(Cpp, Java, Python)
  • 可扩展

官方文档

 

3.2 Boost.Serialization

Boost.Serialization可以创建或重建程序中的等效结构,并保存为二进制数据、文本数据、XML或者有用户自定义的其他文件。该库具有以下吸引人的特性:

  • 代码可移植(实现仅依赖于ANSI C++)。
  • 深度指针保存与恢复。
  • 可以序列化STL容器和其他常用模版库。
  • 数据可移植。
  • 非入侵性。

 

3.3 MFC Serialization

Windows平台下可使用MFC中的序列化方法。MFC 对 CObject 类中的序列化提供内置支持。因此,所有从 CObject 派生的类都可利用 CObject 的序列化协议。

MSDN中的介绍

 

3.4 .Net Framework

.NET的运行时环境用来支持用户定义类型的流化的机制。它在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。


3.5 简单总结

这几种序列化方案各有优缺点,各有自己的适用场景。其中MFC和.Net框架的方法适用范围很窄,只适用于Windows下,且.Net框架方法还需要.Net的运行环境。参考文献1从序列化时间、反序列化时间和产生数据文件大小这几个方面比较了前三种序列化方案,得出结论如下(仅供参考):

  • Google Protocol Buffers效率较高,但是数据对象必须预先定义,并使用protoc编译,适合要求效率,允许自定义类型的内部场合使用。
  • Boost.Serialization 使用灵活简单,而且支持标准C++容器。
  • 相比而言,MFC的效率较低,但是结合MSVS平台使用最为方便。

为了考虑平台的移植性、适用性和高效性,推荐大家使用Google的protobuf和Boost的序列化方案,下面介绍我使用这两种方案的心得及注意事项。


4. 最常用的两种序列化方案使用心得

关于这两种方案的具体使用和示例没什么好写的,因为优秀的参考资料很多,请看后面给出的相关参考资料,这里只给出我使用时的一些心得,方便大家在选择序列化方案时有个正确的参考,避免选择错误,浪费时间。


4.1 Google Protocol Buffers

protobuf相对而言效率应该是最高的,不管是安装效率还是使用效率,protobuf都很高效,而且protobuf不仅用于C++序列化,还可用于Java和Python的序列化,使用范围很广。但在使用过程中要注意两个问题:


(1)protobuf支持的数据类型不是很丰富

protobuf属于轻量级的,因此不能支持太多的数据类型,下面是protobuf支持的基本类型列表,一般都能满足需求,不过在选择方案之前,还是先看看是否都能支持,以免前功尽弃。同样该表也值得收藏,作为我们在定义类型时做参考。

.proto type

c++

notes

double

double

 

float

float

 

int32

int32

使用可变长编码方式,负数时不够高效,应该使用sint32

int64

int64

同上

uint32

uint32

使用可变长编码方式

uint64

uint64

同上

sint32

int32

使用可变长编码方式,有符号的整型值,编码时比通常的int32高效

sint64

sint64

同上

fixed32

uint32

总是4个字节,如果数值总是比2^28大的话,这个类型会比uint32高效

fixed64

uint64

总是8个字节,如果数值总是比2^56大的话,这个类型会比uint64高效

sfixed32

int32

总是4个字节

sfixed64

int64

总是8个字节

bool

bool

 

string

string

一个字符串必须是utf-8编码或者7-bitascii编码的文本

bytes

string

可能包含任意顺序的字节数据

 

(2)protobuf不支持二维数组(指针),不支持STL容器序列化

这个缺陷挺大,因为稍复杂点的数据结构或类结构里出现二维数组、二维指针和STL容器(set、list、map等)很频繁,但因为 protobuf简单的实现机制,只支持一维数组和指针(用repeated修饰符修饰),不能使用repeated repeated来支持二维数组, 也不支持STL,因此在选择该方案之前,一定 要确保你的数据结构里没有这些不支持的类型。


(3)protobuf嵌套后会改变类名称

protobuf支持类的嵌套,即在一个自定义类型中可以定义另一个自定义类型,但注意嵌套的自定义类型在经过protobuf处理后生成的类名称并不是你定义的类名称,而是加上了外层的类名称作为前缀,下面举一个简单的例子:

复制代码
    message DFA {  
required int32 _size = 1;  
message accept_pair {  
required bool is_accept_state = 1;  
required bool is_strict_end = 2;  
optional string app_name = 3;  
}  
repeated accept_pair accept_states = 2;  
}  
复制代码

 

那么嵌套中的accept_pair 生成后的类不是accept_pair 而是DFA_accept_pair 。如果不想改类名称,将accept_pair 拿到外面与DFA平行定义即可。


4.2 Boost.Serialization

Boost库是个很庞大的库,功能非常丰富,序列化只是其中的一个小分支,但为了使用Boost的序列化方案,你需要安装整个Boost库,所花费的磁盘空间和时间都很多,同样支持的序列化功能也很强大,既支持二维数组(指针),也支持STL容器,更不需要我们用某种特殊的格式重新定义我们的类结构,其非侵入的性质使得我们无须改动已有的类结构即可序列化,这时非常赞的一个性质。但是由于体积庞大,安装复杂,如果只是简单的序列化,没必要使用该方案,只有protobuf不能满足你的需求时,才应该考虑该方案。


(1)安装boost库遇到的一系列问题

安装boost库本事就是一项很费时的工程,如果期间出现了各种错误,更加耗时耗耐心。我们可以从官网下载Boost库的二进制源码进行安装,安装方法可以参考网络或后面我给出的参考资料。

安装过程如下:

首先解压安装包,如果是tar.gz用tar zxvf解压,如果是tar.bz2用tar jxvf解压,解压后进入解压后的目录,依次运行以下命令:

./bootstrap.sh
sudo ./b2 install

注:这里没有指定安装路径,在第二个命令可以加入--prefix指定安装目录。

 

安装时的注意事项:

注意1:要用root权限进行安装,否则会在安装过程中报错,提示权限不足。

注意2:boost库的安装依赖一些环境,通常有Python、bzip2和zlib,它们所在的软件包分别为:

Ubuntu下:

zlib1g-dev 
libbz2-dev 
libpython2.7-dev (and libpython3.3-dev)

 

Fedora/Redhat下:

zlib-devel 
libbz2-devel 
python-devel (and python3-devel) 


这也是安装过程中报错的主要来源。

报错1:如果Python库不完整,可能会报“ fatal error: pyconfig.h: No such file or directory compilation terminated.”或者“fatal error: patchlevel.h: No such file or directory”错误。解决方法如下:

Fedora系统:sudo yum install python-devel

Ubuntu系统:sudo apt-get  install python-dev


报错2:报错 “ libs/iostreams/src/bzip2.cpp:20:56: fatal error: bzlib.h: No such file or directory”,解决方案:

Fedora系统:sudo yum install bzip2-devel

Ubuntu系统或Debian系统:sudo apt-get install libbz2-dev


通常对于这些错误,在Ubuntu系统下一般可以通过sudo apt-get install libboost-all-dev全部解决,但不一定行得通。


(2)安装成功后,如果未指定安装位置,那么默认将会安装到/usr/local/lib和/usr/local/include下,那么我们在使用Boost库进行编译时就需要使用-L和-I参数加上具体的lib和include路径,像下面这样:

g++ -o test boost_test.cpp -I$BOOST_INCLUDE -L$BOOST_LIB -lboost_serialization

如果觉得每次都这样很麻烦,那么可以将我们所要用到的lib和include文件加入到环境变量中,像下面这样:

sudo cp /usr/local/lib/libboost_serialization.* /usr/lib
sudo cp -r /usr/local/include/boost /usr/include

然后在编译时直接g++ -o test boost_test.cpp -lboost_serialization即可。

注意:boost下面有两个序列化lib文件:ibboost_serialization.lib 和 libboost_wserialization.lib,那么这两者有什么区别呢?

其实'w' 表示使用的是宽字符,例如 wchar_t。


(3)boost不尽人意的地方

  • 基本类型指针很难序列化,例如int *array,官网上是这么说的:
    By default, data types designated primitive byImplementation Levelclass serialization trait are never tracked. If it is desired totrack a shared primitive object through a pointer (e.g. alongused as a reference count), It should be wrappedin a class/struct so that it is an identifiable type.The alternative of changing the implementation level of alongwould affect alllongs serialized in the wholeprogram - probably not what one would intend.
    也就是说如果你想序列化原生类型的指针,需要给其加上struct或class使其变为类类型再序列化,可见有些麻烦,这样的需求往往也很频繁,鉴于序列化机制的实现原理,boost库暂时还不能很好的支持基本类型的指针序列化。
  • 不能序列化变长数组(variable-sized array),会报错说变长数组不是模板类类型。


(4)如果需要定义一个对象数组,如定义含有2个元素的class A对象数组,那么必须用A a[2]定义而不能用对象的指针A *a = new A[2]定义,这样序列化a后默认当作一个A对象处理,因此只能存储一个对象的值,后面的不会存储。


(5)所谓boost很人性的非侵入性质也有一定的条件:如果不想改动原来的类,那么原来的类属性必须是public的,这很容易解释,因为你必须 要能在别处访问到这些属性并定义其序列化方式,当然这也在其它地方暴露了类的结构,具有一定的劣势。这样的条件往往很难满足,因为我们定义的类属性一般都 是private的,如果是这样,且仍想要使用非侵入性质,那么需要在类中添加以下声明来开放访问给 serialization 库:

friend class boost::serialization::access; 

这样的方式比让成员public更好。


参考资料

    • 常见的三种C++序列化方案对比
    • c++对象序列化初步探讨
    • 官方介绍:Google Protocol Buffers
    • Google Protocol Buffers中文教程
    • Protocol Buffers的应用与分析
    • 玩转Protocol Buffers
    • Boost:Getting Started on Unix Variants
    • linux平台上编译安装boost库(新浪博客)
    • Boost Serialization 库
    • Boost C++库 - 序列化
    • Boost - 序列化 (Serialization)
    • Boost - Serialization序列化


作者:Alexia(minmin) 
如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】 
如果您希望与我交流互动,欢迎微博互粉 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SCCM 2012系列16 操作系统播发⑤

添加了操作系统映像,也创建了任务序列,那么我们改对创建的任务序列编辑一下了,以满足我们播发下去系统的要求是我们想要的,比如分区是怎么样的,当然分区不是固化的,是按照百分比来进行划分的,详…

vue旋转图片功能,旋转放大图片功能;vue旋转放大div元素

需求&#xff1a;可以旋转、放大、颠倒图片。 html: <div class"imgtop"><img class"imgboxele" id"xingshizhengzhengben" :src"imgurl" alt""></div><div class"imgtxt">行驶证正本<…

xp和win7安装telnet服务

xp&#xff1a; 有些ghost版本的xp会精简掉telnet服务 首先telnet服务需要的几个文件&#xff1a; tlntadmn.exe tlntsess.exe tlntsvr.exe tlntsvrp.dll 文件分享&#xff1a;https://yunpan.cn/cSaaaXjUrKFHu 访问密码 719d 将以上几个文件拷贝到c:\windows\system32下&…

linux centos7.2 nodeJs全局安装

先下载nodeJS 选一个linux版本的http://nodejs.cn/download/ 下载下来得到个node-v8.12.0-linux-x64.tar.xz这样的文件 用xftp上传到服务器你想安装的目录 xftp破解版链接:http://www.xue51.com/soft/1456.html xshell破解版链接:http://www.cncrk.com/downinfo/219821.html …

WebView 和JS 之间交互

2019独角兽企业重金招聘Python工程师标准>>> 1.android中利用webview调用网页上的js代码。 Android 中可以通过webview来实现和js的交互&#xff0c;在程序中调用js代码&#xff0c;只需要将webview控件的支持js的属性设置为true&#xff0c;&#xff0c;然后通过lo…

【libjpeg.lib】在Windows7下编译生成libjpeg.lib

一、准备&#xff1a; 下载最新的jpeg库源码&#xff1a;http://www.ijg.org/files/jpegsr9a.zip 二、编译 1. 解压到指定目录&#xff0c;我是&#xff1a;E:\program\opensource\jpeg-9a-win 2. 打开VS2010命令行窗口(为了得到VS2010的环境)&#xff0c;并切换到E:\program…

uni-app图片加水印;小程序图片添加水印;使用canvas上传图片加水印

原博主&#xff1a;点击查看 需求&#xff1a; 微信小程序&#xff0c;上传图片&#xff0c;成功后图片有水印&#xff0c;既图片的网络地址也有水印。 上传图片使用uni-app的uni.chooseImage&#xff08;&#xff09;方法&#xff0c;水印是用canvas。 以下代码可以直接使用…

vue或js解析文件excel表格js通过插件解析表格读取文件

安装插件 cnpm i xlsx --save-dev cnpm i jquery --save-dev 引入插件 html引入文件 <input type"file" id"excel-file" value"file"/> dom加载完成解析文件 mounted() {$(#excel-file).change(function(e) {var files e.target.fi…

微信小程序request请求封装;微信小程序封装request请求;uni-app小程序封装request请求;

本片封装了微信小程序request请求&#xff1b;为别是post get put请求&#xff0c;重点在request.js文件 1.新增四个文件 2.根目录下的utils下的request.js封装uni.request()请求 2.1 manifest.json&#xff1a;解决H5浏览器跨域问题-----配置代理一定要重启项目 // 自定义配…

关“视觉神经系统是怎么形成的?”的思考

http://www.cnblogs.com/mrxsc/p/5571358.html 视觉信息的处理是一个非常复杂的过程&#xff0c;这不由得让我想到了同样位于人们大脑中的新大脑皮层&#xff0c;作为人类智能的起始之地&#xff0c;它的运作也不简单&#xff0c;但是在婴儿时期&#xff0c;它的各部分单元并没…

uni-app控制小程序版本更新;小程序自动更新版本;uni-app发布新版本后仍旧是老版本问题

问题&#xff1a; 首先小程序&#xff0c;更新版本发布后&#xff0c;用户的版本一般情况下仍是旧版本&#xff1b;需要手动删除小程序后&#xff0c;在重新搜索打开才能使用新版本&#xff1b; 原因查看&#xff1a; 运营机制&#xff1b;更新机制&#xff1b; 解决办法&…

浅尝boost之format

From: http://www.cnblogs.com/WuErPIng/archive/2005/04/21/142308.html 概述 std::string是个很不错的东东&#xff0c;但实际使用时基本在每个程序里都会遇到不愉快的事情&#xff1a;格式化字符串。我甚至由于这个原因在代码里引入平台有关的MFC&#xff0c;ATL等本…

nuxt 服务器构建因太耗CPU进程被杀解决办法

在本地打包然后上传到github 再下载到服务器 如果你项目中有.gitignore那把里面的.nuxt删了(.gitignore是设置GIT不上传的文件)并把dist改为/dist 然后用git或者sourcetree上传项目到github&#xff0c;我这里用的sourceTree 上传完成 到服务器把项目下载下来 我这用的linu…

实用的rpm网站

http://www.rpmfind.net和 http://rpm.pbone.net/转载于:https://blog.51cto.com/nickcoco/993222

在VisualStadio2015上使用EF6.0建立MySql数据库

1.新建工程 2.建立类的文件夹DAL 3.建立相关类 【Student类】 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace ETTest3{ public class Student { public int Id { get; set; } public string La…

固定列表的表格

固定的行&#xff1a;行名称不一样&#xff0c;每一个值对应赋值 html&#xff1a; <el-table class"table-box" :data"allObj.peoArr"><el-table-column prop"name" min-width"130"></el-table-column><el-ta…

拼图算法分析...

From: http://blog.sina.com.cn/s/blog_6a4b57e30100mfch.html 一、题目说明&#xff1a;   &#xff08;九宫问题&#xff09;在一个&#xff13;&#xff13;的九宫中有&#xff11;&#xff0d;&#xff18;这&#xff18;个数及一个空格随机的摆放在其中的格子里&#…

uni-app小程序本地打包超过2M不能预览问题;小程序打包过大不能预览和真机调试;uni-app分包;

一、问题&#xff1a;我们在小程序工具中开发时候&#xff0c;需要本地打包&#xff0c;但是当本地的打包文件大于2M时候&#xff0c;预览的二维码就会有问题&#xff0c;导致真机扫码打不开或者有遗漏。 二、此时就需要开启分包 1.微信小程序每个分包的大小是2M&#xff0c;总…

Asp.Net MVC开源CMS - Orchard

最近在学习Asp.Net MVC, 一直是step by step地看官方文档。 想找个成熟的MVC开发的开源系统&#xff0c;系统学习一下MVC, 搜索了一下&#xff0c;惊喜的发现了Orchard. 这个是介绍 2011/01/21号发布的关于Orchard的介绍&#xff0c;说明Orchard还是一个非常新鲜的事物。以后会…

拼图游戏及其相关算法

From: http://blog.sina.com.cn/s/blog_4ed8b87701011c6x.html 这个问题其实可以简单表述成&#xff0c;3*3的格子装了1至8&#xff0c;8个数字&#xff0c;数字是随机分布于各个格子中&#xff0c;问是否可以利用空格的格子&#xff0c;移动装有数字的格子最终达到某种序列&a…