mfc怎么使⽤xml_最常⽤的两种C++序列化⽅案的使⽤⼼得今天说说最常⽤的(protobuf和boost serialization)两种C++序列化⽅案的使⽤⼼得
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⽀持的基本类型列表,⼀般都能满⾜需求,不过在选择⽅案之前,还是先看看是否都能⽀持,以免前功尽弃。同样该表也值得收藏,作为我们在定义类型时做参考。
(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 boolis_accept_state =1;
required boolis_strict_end =2;
optional stringapp_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)安oost库遇到的⼀系列问题
安oost库本事就是⼀项很费时的⼯程,如果期间出现了各种错误,更加耗时耗耐⼼。我们可以从官⽹下载Boost库的⼆进制源码进⾏安装,安装⽅法可以参考⽹络或后⾯我给出的参考资料。
安装过程如下:
⾸先解压安装包,如果是⽤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 by Implementation Levelclass serialization trait are never tracked. If it is desired totrack a shared primitive object through a pointer (e.g. along used 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++ Linux服务器架构师学习资料加获取(资料包括C/C++,Linux,golang技
术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
java xml是什么
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论