跳到主要内容

Serialization and Deserialization / 序列化与反序列化

源文档地址

序列化是把数据结构翻译成某种格式(文本或一串字节)的过程,以便存储(比如存进文件)或传输(比如通过网络),之后再重建出来。相反的操作 —— 从序列化的格式里把数据结构提取回来 —— 叫作反序列化。

来自维基百科

常见格式

做这件事的方法有很多,但常用的文本序列化格式有三种:XMLJSONCSV。二进制格式通常更小,因而读写更快;而文本格式的好处是人能读懂,这对调试和版本管理都有帮助。跟网络打交道时,通常会选 JSON —— 它很容易用 JavaScript 解析和生成。

自动

当你只需要把数据结构通过网络从应用的一个实例发给另一个实例、数据并不需要存进磁盘时,你多半不在意实际用的是什么格式。

这种情况下,你可以用现成的运行时序列化器 —— 它们能直接序列化大多数数据类型,不需要你为序列化另建一套数据结构。这样又快又省事,代价是你对格式没有任何控制权,因而在体积上可能有些开销:序列化过程可能会把一些你根本不需要序列化的数据也算进去。

序列化成 XElement(也就是 XML)时,最好用 System.Serialization 目录下的这些节点:

  • Serialize → XElement → Deserialize
  • Serialize (Log Errors) [Advanced] → XElement → Deserialize (Log Errors)

此外,VL.Serialization.FSPickler 这个包里的下列节点也可以用:

  • Serialize (XML) → String → Deserialize (XML)
  • Serialize (JSON) → String → Deserialize (JSON)
  • Serialize (Binary) → MutableArray of Byte → Deserialize (Binary)
备注

这些节点生成的序列化格式是「易变的」—— 也就是说它在 VL 的不同版本之间可能并不兼容。

另外:如果一份 JSON 或 XML 不是由对应的 Serialize 节点生成的,而其中各个属性又没有按字母顺序排列,那么反序列化会失败!这是 FsPickler 的一个怪癖,因此我们大概在某个时候得把它换掉。在那之前,碰上这类情况你不妨考虑改用 Json.NET 库里的节点。

如果你想更多了解这些节点内部是怎么工作的,去看它们所基于的 FSPickler(英文)库的文档。

(上游此处待补图:MyType 被自动序列化和反序列化的例子)

手动

当你要把程序的状态存进磁盘时,你可能得考虑文件格式的不同版本 —— 因为你所保存的数据结构会随时间演变,而你多半仍希望你的应用能打开早先版本存下的文件。

这种情况下你会想自己定义格式:格式什么时候改由你说了算,序列化和反序列化过程相应调整,并且可以通过为不同版本的格式提供不同的序列化/反序列化器来保住向后兼容。

自定义序列化

下面这些节点让你能搭出数据结构:

  • XElement (Join) [XML]
  • XAttribute (Join) [XML]

然后用这些节点把它序列化成字符串格式:

  • ToJSON [XML]
  • ToString [XML]

或者用这些节点直接存进磁盘:

  • FileWriter (JSON) [IO]
  • FileWriter (XML) [IO]

另建一套只用于序列化的数据结构是一份开销,但也有好处:你可以把不需要序列化的东西留在外面,并且精确定义最终格式长什么样。

(上游此处待补图:一个数据结构,以及它序列化成 XML 和 JSON 字符串的样子)

自定义反序列化

下面这些节点让你能从磁盘读取 JSON 或 XML 文件:

  • FileReader (JSON) [IO]
  • FileReader (XML) [IO]

或者把 JSON、XML 字符串解析成 XElement 结构:

  • ParseJson [XML]
  • Parse [XML]

然后用下面这些节点访问数据结构里的各个字段:

  • XElement (Split) [XML]
  • XAttribute (Split) [XML]
  • XElementsByName [XML]
  • XPathSelectElement [XML]
  • XPathSelectElements [XML]
  • XPathEvaluate [XML]

(上游此处待补图:对给定的 json/xml 做反序列化)