Next: , Previous: The write barrier, Up: R Internal Structures



1.8 序列化形式

R对象的序列化版本被load/save使用。 在底层,则被.saveRDS/.readRDSserialize/unserialize 使用。 这取决于将被序列化的对象(文件,连接,原味向量)以及市序列化 一个对象还是一个对象集合(通常是一个工作空间)。 save写一个信息头在文件的开端(一个以LF结尾的行) 注明格式信息,而低层次的版本不会这样做。

R 在2001年12月份的R 1.4.0后就使用一样的序列化格式。 load 仍然支持早期信息的读取,但在这里我们不会讨论。 (这些格式的文件在包的data目录下面仍然可以看到) 当前序列化的格式被称为 `版本 2',并且从 R 1.4.0开始向后兼容。比如,支持附加的 SEXPTYPE

save()首先创建一个被保存对象的加有便签的成对列表, 然后保存这个对象并且在前面加单行的信息头(二进制保存 的时候通常加RDX2\n)。 load() 读取信息头,对单个对象进行去序列化(一个成对列表 或者一个向量列表),在适当的环境中能分配列表的元素。

R里面的序列化需要考虑到对象也可能含有对环境的引用(references), 而这些引用随后可能会附上环境等。 (作为包或者命名空间的环境以名字保存。) 此外,还有在拷贝上没有重复但在去序列化时保持共享的 `引用对象'(reference object)。 这些是弱引用,其它外部指针和环境都和包 ,命名空间和全局环境相关。 这些通过哈希表来操作。在第一个之后的引用以 通过表格条目建立索引且以参考符号(reference marker) 的方式写出。

序列化首先写一个信息头表明格式( 一个XDR格式的二进制保存通常是X\n) 以及格式和两个R版本的版本号(以整数的方式)。 (去序列化需要解释这两个版本,因为 生成这个文件的R版本跟随着可以 读这种格式的最小R版本。) 序列化然后用文件src/main/serialize.c中的 函数WriteItem递归写出对象。

一些对象被写出时就像它们是SEXPTYPE: 这种假SEXPTYPE包括了R_NilValue, R_EmptyEnv, R_BaseEnv, R_GlobalEnv, R_UnboundValue, R_MissingArgR_BaseNamespace

对所有除NILSXPSYMSXPENVSXP 外的 SEXPTYPE,序列化 从二进制位0:7 1的一个整数开始, 随后是对象二进制位,两个二进制位表明是否有一些属性以及是否有标签(成对列表类型), 一个没有用到的二进制位,然后是12:27的gp 字段 2 成对列表类似的对象写入它们的属性(如果有), 标签(如果有),CAR,然后CDR(使用尾部递归): 其它对象在它们自身后面写入属性。 原子性向量对象在他们数据后面写入它们的长度: 泛型向量-列表对象在对每个元素调用WriteItem后写入长度。 对于 CHARSXP 的特例 NA_STRING, 写入它的长度 -1 但没有数据。

环境从多个角度处理:如前所示,一些环境当作 特殊的假-SEXPTYPE写入。包和命名空间 的环境就是以假-SEXPTYPE写入,随后是 它们的名字。。 `常规'环境以ENVSXP写出,并且包括 一个整数表明环境是否被锁住,随后是 外围(enclosure),框架,标签和属性。


Footnotes

[1] 对于SEXPTYPE,目前只有 0:4 被使用了,但值 241:255 用于假SEXPTYPE

[2] 现在,唯一相关的二进制位是 0:1, 4, 14:15。