Serialization and Deserialization / 序列化与反序列化
序列化是把数据结构翻译成某种格式(文本或一串字节)的过程,以便存储(比如存进文件)或传输(比如通过网络),之后再重建出来。相反的操作 —— 从序列化的格式里把数据结构提取回来 —— 叫作反序列化。
来自维基百科
常见格式
做这件事的方法有很多,但常用的文本序列化格式有三种:XML、JSON 和 CSV。二进制格式通常更小,因而读写更快;而文本格式的好处是人能读懂,这对调试和版本管理都有帮助。跟网络打交道时,通常会选 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 做反序列化)