为什么需要对结构体进行序列化和反序列化操作,以c++语言为例

目录标题

  • 1. 引言
  • 2. 原因细分析
    • 2.1 结构体中含有指针元素
    • 2.2 不同计算机上大端,小端存储问题以及数据结构所占字节问题
    • 2.3 可读性问题
  • 3. 总结

1. 引言

  思考这一问题的起源,在于看到leetcode中的一道题目297. Serialize and Deserialize Binary Tree。之前在学C/C++的时候,有这样的两个函数

// 读取文件块数据

size_t fread(void *buffer, size_t size, size_t count, FILE *file);

// 写入文件块数据

size_t fwrite(const void *buffer, size_t size, size_t count, FILE *file);

貌似这两个函数就可以实现一种“通用”的“序列化”和“反序列化”的操作:无论什么结构体,都以文件块的形式写入磁盘中(或者送入网络);无论什么结构体,在从磁盘中(或者网络中)读取到文件块之后,都以原始结构体的协议装载到内存中。那么还要特意设计序列化和反序列化的意义是什么呢?经过思考后,序列化和反序列化操作需要特定设计的原因,有3点:

  1. 结构体中含有指针元素
  2. 不同计算机上大端,小端存储问题以及数据结构所占字节问题
  3. 可读性问题

2. 原因细分析

2.1 结构体中含有指针元素

  以tree为例子,结构体中含有left和right指针。

struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
}

为什么需要对结构体进行序列化和反序列化操作,以c++语言为例_第1张图片

对于上图所示的tree,我们通常以head指代整个tree。如果通过fwrite将head保存为一个二进制文件tree.bin。在另外一台电脑上,fread该bin文件,仅仅能获得根节点1,其他子节点会“断掉”。序列化和反序列化的操作就可以解决该问题。
为什么需要对结构体进行序列化和反序列化操作,以c++语言为例_第2张图片
  如果,我们将其序列化为一个txt,而这txt中的内容是该tree的中序遍历结果和前序遍历结果,就可以根据该txt在任意电脑上复原(反序列化)原始tree。

2.2 不同计算机上大端,小端存储问题以及数据结构所占字节问题

  即使struct中不含有指针型数据成员,依旧可能会存在问题,如下所示一个普通的结构体。

struct A{
int age;
char height;
int weight;
}

如果通过fwrite的方式保存为A.bin。在另一台电脑上fread的时候依旧可能会出现问题。主要原因会涉及两方面:虽然大部分电脑上int占4个字节,但并不绝对,特殊情况下会是2或8?。另外一方面是编译器会对字节进行自动补齐的原因。上述两点原因会导致fread的时候出现混乱现象。
  解决该问题的方法,同样可以通过设计序列化和反序列化操作来达到。例如序列化的时候就可以将该结构体,保存为A.txt形式:

18    180    75

反序列化,则是读取txt然后复原结构体。

2.3 可读性问题

  最后一个原因就是可读性问题。序列化的结果一般可以方便的以人类能够接受的形式更好的阅读。

3. 总结

  序列化操作看似费心,需要自己来设计。但一旦设计出来,代码的鲁棒性,序列化之后的可读性都会更优雅。反观直接的fwrite和fread这种“偷懒”的做法,则是一种比较“快糙猛”的做法,会有较多的隐患存在。

你可能感兴趣的:(从码农到软件工程师,c++,数据结构,算法,序列化,fwrite)