Ruby 2.4

Marshal Format

Marshal 格式

统帅格式用于序列化 ruby 对象。格式可以通过三个用户定义的扩展机制存储任意对象。

有关使用 Marshal 来序列化和反序列化对象的文档,请参阅 Marshal 模块。

这个文档调用一个序列化的一组对象流。Ruby 实现可以从字符串,IO 或实现getc方法的对象中加载一组对象。

Stream Format

流的前两个字节包含主要版本和次要版本,每个版本都作为编码数字的单个字节。在 Ruby 中实现的版本是4.8(存储为“x04x08”),并受到 Ruby 1.8.0和更高版本的支持。

统一格式的不同主要版本不兼容,不能被其他主要版本理解。更新的次要版本可以理解较小版本的格式。格式4.7可以通过4.8实现加载,但格式4.8不能通过4.7实现加载。

版本字节后面是描述序列化对象的流。该流包含嵌套对象(与 Ruby 对象相同),但流中的对象不一定有直接映射到 Ruby 对象模型。

流中的每个对象都由一个字节来描述它的类型,后面跟着一个或多个描述该对象的字节。当下面提到“对象”时,它意味着下面定义 Ruby 对象的任何类型。

true, false, nil

这些对象每个都是一个字节长。“T”t表示true,“F”t表示false,“0”表示nil

Fixnum and long

“i”表示使用打包格式的带符号32位值。类型后面有一到五个字节。加载的值将始终是 Fixnum。在32位平台上(Fixnum 的精度小于32位),加载较大的值会导致 CRuby 溢出。

fixnum 类型用于表示 ruby Fixnum 对象以及编组数组,哈希,实例变量和其他类型的大小。在下面的章节中,“long” 意味着下面描述的格式,它支持完整的32位精度。

第一个字节有以下特殊值:

“x00”

整数的值是0.没有字节。

“x01”

整数的总大小是两个字节。接下来的字节是一个范围在0到255之间的正整数。只有123到255之间的值应该用这种方式表示来保存字节。

“xff”

整数的总大小是两个字节。以下字节是-1到-256范围内的负整数。

“x02”

整数的总大小是三个字节。以下两个字节是一个正的小端整数。

“xfe”

整数的总大小是三个字节。以下两个字节是一个负的小端整数。

“x03”

整数的总大小是四个字节。以下三个字节是一个正的小端整数。

“xfd”

整数的总大小是两个字节。以下三个字节是一个负的小端整数。

“x04”

整数的总大小是五个字节。以下四个字节是一个正的小端序整数。为了与32位红宝石兼容,只有小于1073741824的 Fixnums 应该以这种方式表示。对于流对象的大小,可以使用全精度。

“xfc”

整数的总大小是两个字节。以下四个字节是一个负的小端整数。为了与32位红宝石兼容,只有大于-10737341824的tFixnumst应该以这种方式表示。对于流对象的大小,可以使用全精度。

否则,第一个字节是带有偏移量的符号扩展8位值。如果该值为正数,则通过从该值中减去5来确定该值。如果该值为负值,则通过将该值加5来确定该值。

有许多值的多种表示形式。CRuby 总是输出尽可能最短的表示。

符号和字节序列

“:”代表一个真实的符号。真正的符号包含为流的其余部分定义符号所需的数据,因为流中未来的出现将代之以引用(符号链接)。该引用是一个零索引的32位值(因此第一次出现:hello为0)。

类型后的字节是字节序列,它由一个长整数组成,表示序列中的字节数,后跟多个字节的数据。字节序列没有编码。

例如,以下流包含符号:hello

"\x04\x08:\x0ahello"

“;”表示引用先前定义的符号的符号链接。类型字节后面是一个包含链接(引用)符号的查找表中的索引的长整型。

例如,以下流包含[:hello, :hello]

"\x04\b[\a:\nhello;\x00"

当下面引用“符号”时,它可以是实际符号或符号链接。

对象引用

与符号引用分离但类似,流只包含除 true,false,nil,Fixnums 和 Symbols 之外的所有对象(由object_id确定)的每个对象的一个​​副本(其单独存储,如上所述)一个索引为32当再次遇到该对象时,该位值将被存储并重新使用。(第一个对象的索引为1)。

“@”代表一个对象链接。在类型字节之后是给出对象索引的长整型。

例如,以下流包含"hello"两次相同对象的数组:

"\004\b[\a\"\nhello@\006"

变量实例

“I” 表示实例变量跟随下一个对象。一个对象在类型字节之后。跟在对象之后的是指示对象的实例变量的数量的长度。长度后面是一组名称 - 值对。名称是符号,而值是对象。这些符号必须是实例变量名称(:@name)。

一个对象(下面描述的“o”类型)为其实例变量使用相同的格式,如此处所述。

对于字符串和正则表达式(如下所述),使用特殊的实例变量:E来指示编码。

扩展

“e”表示下一个对象被模块扩展。一个对象在类型字节之后。在对象之后是一个包含对象扩展模块名称的符号。

Array

“[”代表一个数组。类型字节后面是一个长整数,表示数组中的对象数量。给定数量的对象跟随着长度。

Bignum

“l” 代表由三部分组成的 Bignum:

sign

一个字节包含正值的“+”或负值的“ - ”。

length

长整数表示 Bignum 数据的字节数除以2。将长度乘以2以确定后续数据的字节数。

data

代表数字的 Bignum 数据字节。

下面的 ruby 代码将从字节数组中重建 Bignum 值:

result = 0 bytes.each_with_index do |byte, exp| result += (byte * 2 ** (exp * 8)) end

类和模块

“c” 表示一个 Class 对象,“m” 表示一个 Module,“M” 表示一个类或模块(为了兼容性,这是旧式的)。没有包含类或模块内容,这种类型仅供参考。类型字节之后是分别用于查找现有类或模块的字节序列。

实例变量不允许在类或模块上使用。

如果没有类或模块存在,应该引发异常。

对于 “c” 和 “m” 类型,加载的对象必须分别是类或模块。

“d” 代表一个数据对象。(数据对象包装来自ruby扩展的指针。)类型字节后面是一个符号,指示 Data 对象的类以及包含 Data 对象状态的对象。

转储数据对象 Ruby 调用 _dump_data。要加载一个 Data 对象,Ruby 会在新分配的实例上调用 _load_data 和对象的状态。

Float

“f” 代表一个 Float 对象。类型字节后面是一个包含浮点值的字节序列。以下值是特殊的:

“inf”

正无穷

“-inf”

负无穷

“nan”

不是数字

否则,字节序列包含一个 C double(可由strtod(3)加载)。Marshal 的较小版本还存储了额外的尾数以确保跨平台的可移植性,但4.8不包含这些版本。看到

ruby-talk:69518

作一些解释。

哈希和哈希默认值

“{”代表一个哈希对象,而“}”代表一个默认值为set(Hash.new 0)的哈希。类型字节之后是长整型,表示哈希中的键值对的数量,即大小。给定数量的对象加倍。

对于具有默认值的哈希,默认值将遵循所有对。

模块和旧模块

Object

“o”表示没有任何其他特殊形式(如用户定义或内置格式)的对象。类型字节后面是一个包含对象类名的符号。类名后面是一个长整型,表示该对象的实例变量名称和值的数量。将给定数量的对象加倍大小。

对中的键必须是包含实例变量名称的符号。

正则表达式

“/”代表一个正则表达式。类型字节后面是一个包含正则表达式源的字节序列。类型字节后面是一个包含正则表达式选项的字节(不区分大小写等)作为有符号的8位值。

正则表达式可以通过实例变量附加一个编码(参见上文)。如果没有编码附加转义为下面的正则表达式特殊功能不存在于 ruby1.8必须删除:gm,oq,u,y,E,F,HL,NV,X,Y.

String

'“'代表一个字符串。类型字节后面是一个包含字符串内容的字节序列。从 ruby 1.9转储时,:E除非编码是二进制编码,否则应该包含编码实例变量(请参见上文)。

Struct

“S” 表示一个 Struct。类型字节后面是一个包含结构名称的符号。名称后面是长整型,表示结构中成员的数量。跟随成员计数的对象数量加倍。每个成员是一对包含成员的符号和该成员的值的对象。

如果结构名称与运行的 ruby 中的 Struct 子类不匹配,则应引发异常。

如果当前运行的 ruby 中的结构与编组结构中的成员计数不匹配,则应该引发异常。

User Class

“C”表示 String,Regexp,Array 或 Hash 的子类。类型字节后面是一个包含子类名称的符号。名称后面是包装的对象。

User Defined

“u” 代表使用_dump实例方法和_load类方法使用用户定义的序列化格式的对象。类型字节后面是一个包含类名称的符号。类名后面是一个包含对象的用户定义表示的字节序列。

类方法_load在类中使用从字节序列创建的字符串调用。

User Marshal

“U” 表示使用marshal_dumpmarshal_load实例方法使用用户定义的序列化格式的对象。类型字节后面是一个包含类名称的符号。类名后面是一个包含数据的对象。

加载新实例时必须进行分配,并且marshal_load必须在数据实例上调用。