需要使用到序列化场景的需求

  • 在写代码的过程中,经常会需要把代码层面的对象数据保存到文件,而这些数据会以各种格式存储.例如:json,xml,二进制等等.二进制,相比json,xml格式,直接把字节copy到硬盘,所以这实现起来相对容易.

例子

  • 下面是一个简单的三维向量结构体,如何把它序列化到文件呢?

struct Vec3 {float x;float y;float z;
}
Vec3 v;
v.x = 1.0f;
v.y = 2.0f;
v.z = 3.0f;
os.write((const char *)&v, sizeof(Vec3));
  • 上述是序列化Vec3对象数据到文件的代码,非常直接.它的内存布局是3个浮点型变量紧凑排列,要把它存储到硬盘,只要从头到尾按字节拷贝即可.但是,在实际开发中,要序列化的对象不可能全部都是内存紧凑排列的,例如STL容器.
std::vector<Vec3> vec;
  • 如果将容器变量从头到尾拷贝到文件,必然会出现错误.因为容器内部通过一个指针来访问存储的对象,而直接拷贝这个容器,只会把指针拷贝,指针指向的数据却丢失了.但是,容器提供了一个可以直接访问指针指向数据的接口,可以通过这个接口得到数据然后直接拷贝.
os.write((const char *)&vec, vec.size() * sizeof(Vec3));        //  错误, 仅拷贝指针
os.write((const char *)vec.data(), vec.size() * sizeof(Vec3));  //  正确, 数据被完全拷贝
  • 通过这个方法就可以得到正确的拷贝结果了.通常,好的做法是将序列化和反序列化封装成接口,以便于使用,如何封装接口,就是这篇文章的主题.从上述两个例子可以发现,对于单体对象和数组对象,编写的代码是不一样的,单体对象直接拷贝,数组对象需要通过 .data() 取得数据地址再进行拷贝.而考虑到还有嵌套数组像 std::vector<std::vector<Vec3>>.对于嵌套数组序列化的代码可能如下:
std::vector<std::vector<Vec3>> vec2;
for (auto & vec: vec2)
{os.write((const char *)vec.data(), vec.size() * sizeof(Vec3));
}
  • 可以发现,对嵌套数组对象的序列化代码跟上述2种对象又不一样,考虑到还有N层嵌套的数组对象.此外,在C++中有一个 可平凡复制的概念 ,通俗的说,就是可以直接按字节拷贝的结构称之为 可平凡复制 ,上述的 Vec3 则是一个可平凡复制结构,而STL容器则不是可平凡复制结构,除此之外还有更多不可平凡复制且非容器的结构,故此,如果要封装接口,除了区分单体对象和数组对象,还要区分可平凡复制和不可平凡复制.
void Serialize(std::ostream & os,   const Type & val);  //  序列化
void Deserialize(std::istream & is,       Type & val);  //  反序列化
//  POD
template <class T, typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> N = 0>
void Serialize(std::ostream & os, const T & val)
{os.write((const char *)&val, sizeof(T));
}//  容器
template <class T, typename std::enable_if_t<std::is_same_v<typename T::iterator, decltype(std::declval<T>().begin())> &&std::is_same_v<typename T::iterator, decltype(std::declval<T>().end())>, int> N = 0>void Serialize(std::ostream & os, const T & val)
{unsigned int size = val.size();os.write((const char *)&size, sizeof(size));for (auto & v : val) { Serialize(os, v); }
}//  POD
template <class T, typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> N = 0>
void Deserialize(std::istream & is, T & val)
{is.read((char *)&val, sizeof(T));
}//  容器
template <class T, typename std::enable_if_t<std::is_same_v<typename T::iterator, decltype(std::declval<T>().begin())> &&std::is_same_v<typename T::iterator, decltype(std::declval<T>().end())>, int> N = 0>void Deserialize(std::istream & is, T & val)
{unsigned int size = 0;is.read((char *)&size, sizeof(unsigned int));val.resize(size);for (auto & v : val) { Deserialize(is, v); }
}
  • 以上实现可序列化任意 可平凡拷贝 结构,并且也可序列化任意嵌套层数的STL风格数组.而对于 不可平凡复制 结构,只需要针对该结构重载即可.借助C++强大的类型推导机制和SFINEA机制,可保证类型安全又具备可扩展性.

C++学习 优雅的实现对象到文件的序列化/反序列化 关键字serialize相关推荐

  1. php+打开文件和其子文件,【php学习记录】 引用、打开文件

    [php学习记录] 引用.打开文件 一.PHP echo 和 print 语句 echo 和 print 区别: echo - 可以输出一个或多个字符串 print - 只允许输出一个字符串,返回值总 ...

  2. java学习笔记16--I/O流和文件

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note16.html,转载请注明源地址. IO(Input  Output)流 IO流用来处理 ...

  3. 学习强制删除正在运行的文件

    看雪软件安全论坛 > 软件安全 > 『安全编程论坛』 > [分享]学习强制删除正在运行的文件 PDA 查看完整版本 : [分享]学习强制删除正在运行的文件 yaolibing 200 ...

  4. vba fso读utf 文本_利用FSO对象操作文件

    大家好,我们今日讲解"VBA信息获取与处理"教程中第十八个专题"FSO对象对文件及文件夹的处理"的第二节"利用FSO对象操作文件",这个专题 ...

  5. AIR文件操作(三):使用FileStream对象读写文件

    快速上手例: 例1.读xml var testXML:XML; var file:File = File.documentsDirectory.resolvePath("Mousebomb/ ...

  6. python学习笔记4(对象/引用;多范式; 上下文管理器)

    python学习笔记4(对象/引用:多范式; 上下文管理器) ### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 21. 动态类型:对象/引用 对象和引用: 对象是 ...

  7. java 注解 对象_Java基础-学习使用Annotation注解对象

    Java基础-学习使用Annotation注解对象 注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某 个时刻非常方便地使用这些数据 1-1:基本语法 Java S ...

  8. Servlet的学习之Request请求对象(3)

    本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看R ...

  9. DSP学习(8)—— linker.cmd文件解析

    DSP学习(8)-- linker.cmd文件解析 文章目录 DSP学习(8)-- linker.cmd文件解析 前言 前言 写工程的时候遇到报内存不够的错误,出现在linker.cmd的内存分配se ...

最新文章

  1. mysql命令行各个参数解释
  2. 30秒内便能学会的30个超实用Python代码片段
  3. 上传文本到hdfs上的一些命令
  4. CSS从大图中抠取小图完整教程(background-position应用) (转)
  5. JavaScript学习(六十)—JSON
  6. pp助手苹果版本_PP助手下线,最新ios免越狱旧版APP手机下载方法!
  7. OEIS A098928 数表扩充
  8. Mac版Permute 3(万能视频转换器)
  9. MxNet创建ILSVRC2012.rec文件
  10. HDU 2154:跳舞毯(递推)
  11. walking机器人仿真教程-应用-多点导航结合睡眠功能实现智能取药
  12. Matlab动画模拟分子布朗运动的示例
  13. Python爬虫爬小说《诡秘之主》
  14. pppoe服务器账号和密码是什么,路由器的PPPOE拨号宽带账号和密码是多少?
  15. 高等数学(第七版)同济大学 习题5-4 个人解答
  16. 数据分析师8大经典问题
  17. vscode代码索引_VS Code:自定义代码片断(Snippets)
  18. Excel2007中固定表头或列
  19. 高通 UEFI:ABL(一)
  20. pdfminer库解析,使用pdfminer进行信息抽取

热门文章

  1. 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(Python面向对象的编程)
  2. 【转】阿里技术专家详解 DDD 系列 第一讲- Domain Primitive
  3. 【转】细说.NET中的多线程 (三 使用Task)
  4. SharePoint学习札记[2] — MOSS2007体系结构概述
  5. [你必须知道的.NET]第二十回:学习方法论
  6. 【Python CheckiO 题解】Multicolored Lamp
  7. 观看实验中微型计算机虚拟拆装演示,虚拟仿真实验 北斗一号微机原理虚拟仿真实验系统64位 v3.0...
  8. 【CodeForces - 777C】Alyona and Spreadsheet(思维,前缀和)
  9. 【51Nod - 1416】两点 (dfs 或 并查集+dfs)
  10. 视觉SLAM十四讲(2):初识SLAM