c++ 序列化和反序列化
- 什么是序列化?
- 为什么要序列化?优点在哪里?
- C++对象序列化的四种方法
- Google Protocol Buffers(protobuf)
- MFC Serialization
- Net Framework
- 简单总结
- 举例说明
什么是序列化?
序列化指的是将一个内存对象转化成一串字节数据(存储在一个字节数组中),可用于保存到本地文件或网络传输。反序列化就是将字节数据还原成内存对象。
总结:
- 序列化:将对象变成字节流的形式传出去。
- 反序列化:从字节流恢复成原来的对象。
为什么要序列化?优点在哪里?
简单来说,对象序列化通经常使用于两个目的:
(1) 将对象存储于硬盘上,便于以后反序列化使用;
(2)在网络上传送对象的字节序列
C++对象序列化的四种方法
Google Protocol Buffers(protobuf)
Google Protocol Buffers (GPB)是Google内部使用的数据编码方式,旨在用来取代XML进行数据交换。可用于数据序列化与反序列化。主要特性有:
- 高效
- 语言中立(Cpp, Java, Python)
- 可扩展
能够创建或重建程序中的等效结构,并保存为二进制数据、文本数据、XML或者实用户自己定义的其它文件。该库具有下面吸引人的特性:
- 代码可移植(实现仅依赖于ANSI C++)。
- 深度指针保存与恢复。
- 能够序列化STL容器和其它经常使用模版库。
- 数据可移植。
- 非入侵性。
MFC Serialization
Windows平台下可使用MFC中的序列化方法。MFC 对 CObject 类中的序列化提供内置支持。因此,全部从 CObject 派生的类都可利用 CObject 的序列化协议。
Net Framework
.NET的执行时环境用来支持用户定义类型的流化的机制。它在此过程中,先将对象的公共字段和私有字段以及类的名称(包含类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象全然同样的副本。
简单总结
这几种序列化方案各有优缺点,各有自己的适用场景。当中MFC和.Net框架的方法适用范围非常窄,仅仅适用于Windows下,且.Net框架方法还须要.Net的执行环境。參考文献1从序列化时间、反序列化时间和产生数据文件大小这几个方面比較了前三种序列化方案,得出结论例如以下(仅供參考):
- Google Protocol Buffers效率较高,可是数据对象必须预先定义,并使用protoc编译,适合要求效率,同意自己定义类型的内部场合使用。
- 使用灵活简单,并且支持标准C++容器。
- 相比而言,MFC的效率较低,可是结合MSVS平台使用最为方便。
举例说明
如:
struct student
{
int id;
string name;
};
将一个student对象转换成字节数据存储在ByteArray[20]中称为序列化代码如
int count = 0;
char ByteArray[20];
student s;
= 12;
= "specialist";
memcpy(ByteArray,&,sizeof());
count += sizeof();
memcpy(ByteArray+count,.c_str(),());
count += ();
把字节数据还原成student对象称为反序列化代码如
student ss;
memcpy(&,ByteArray,sizeof());
(ByteArray+4,count-4);
count += ();
其实在上述代码中存在问题只是memcpy函数隐藏了这个细节。在vs的内存窗口中我们可以看到的内存视图为0c 00 00 00(16进制),这似乎和我们想的00 00 00 0c不一样,这就是所谓的大端系统(内存中高位字节在前)和小端系统(内存中低位字节在前),而目前我们的系统大多是小端系统,而一般在网络传输中却规定使用大端传输(如果不规定当我们将0c 00 00 00这四个字节传给对方,对方就不清楚这四个字节的值?0c 00 00 00 or 00 00 00 0c),我们用memcpy函数的时候实际上就是对内存的拷贝,而前面讲了在小端系统中对于这个值拷贝到bytearray中的肯定是0c 00 00 00,然后接收端接收到的是0c 00 00 00以为你发是12的6次方(也不一定如果对端也是用的C语言直接用memcpy将0c 00 00 00拷贝对应的内存,的值还是12,就如上述代码,但是客户端和服务端的语言不一定一样),这显然与你想发的12差太多了 。
于是我们使用位操作(语言无关)来实现序列化与反序列化,以为例代码如(注意位操作针对的是数值本身而非内存不要搞混了)
/*移位之后ByteArray中前四个字节存的便是00 00 00 0c*/
ByteArray[0] = >>24;
ByteArray[1] = >>26;
ByteArray[2] = >>8;
ByteArray[3] = ;
接收端再移回来就行了,代码如
+= ByteArray[0]<<24;
+= ByteArray[1]<<16;
+= ByteArray[2]<<8;
+= ByteArray[3];