Marshal
格式¶ ↑
Marshal
格式用于序列化 Ruby 对象。该格式可以通过三个用户定义的扩展机制存储任意对象。
有关使用 Marshal
序列化和反序列化对象的文档,请参阅 Marshal
模块。
本文档将一组已序列化的对象称为流。Ruby 实现可以从 String
、IO
或实现 getc
方法的对象加载一组对象。
流格式¶ ↑
流的前两个字节包含主版本和次版本,每个字节编码一个数字。Ruby 中实现的版本是 4.8(存储为“x04x08”),ruby 1.8.0 及更高版本支持该版本。
不同主版本的 Marshal
格式不兼容,其他主版本无法理解它们。较低次版本的格式可以被较高次版本理解。4.8 实现可以加载格式 4.7,但 4.7 实现无法加载格式 4.8。
在版本字节后面是一个描述序列化对象的流。该流包含嵌套对象(与 Ruby 对象相同),但流中的对象不一定与 Ruby 对象模型直接映射。
流中的每个对象都由一个字节描述其类型,后跟一个或多个字节描述该对象。当下面提到“对象”时,它表示下面定义 Ruby 对象的任何类型。
true、false、nil¶ ↑
这些对象每个长一个字节。“T”表示 true
,“F”表示 false
,“0”表示 nil
。
Fixnum 和 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 位 ruby 兼容,只有小于 1073741824 的 Fixnum 应该这样表示。对于流对象的大小,可以使用完全精度。
- “xfc”
-
整数的总大小为五个字节。后面的四个字节为负小端整数。为了与 32 位 ruby 兼容,只有大于 -10737341824 的 Fixnum 应该这样表示。对于流对象的大小,可以使用完全精度。
否则,第一个字节是带偏移量的符号扩展八位值。如果值为正,则通过从值中减去 5 来确定值。如果值为负,则通过向值中添加 5 来确定值。
许多值有多个表示形式。CRuby 始终输出最短的可能表示形式。
符号和字节序列¶ ↑
“:” 表示一个真正的符号。真正的符号包含为流的其余部分定义符号所需的数据,因为流中的未来出现将改为对此符号的引用(符号链接)。引用是一个从零开始的 32 位值(因此:hello
的第一次出现为 0)。
类型字节之后是字节序列,其中包含一个指示序列中字节数的长整数,后跟该数量的数据字节。字节序列没有编码。
例如,以下流包含 Symbol
:hello
"\x04\x08:\x0ahello"
“;”表示 Symbol
链接,它引用先前定义的 Symbol
。类型字节之后是长整数,其中包含查找表中链接(引用)的 Symbol
的索引。
例如,以下流包含 [:hello, :hello]
"\x04\b[\a:\nhello;\x00"
当下面引用“符号”时,它可以是实际符号或符号链接。
Object
引用¶ ↑
与符号引用类似但不同,流仅包含每个对象的一个副本(由 object_id 确定),但 true、false、nil、Fixnum 和 Symbol(如上所述单独存储)除外,当再次遇到对象时,将存储和重用一个从 1 开始的 32 位值。(第一个对象的索引为 1)。
“@”表示对象链接。类型字节之后是长整数,给出对象的索引。
例如,以下流包含一个 Array
,其中包含相同的 "hello"
对象两次
"\004\b[\a\"\nhello@\006"
实例变量¶ ↑
“I”表示实例变量紧随下一个对象之后。对象紧随类型字节之后。对象之后是长度,指示对象中实例变量的数量。长度之后是一组名称-值对。名称是符号,而值是对象。符号必须是实例变量名称(:@name
)。
Object
(“o”类型,如下所述)对其实例变量使用此处描述的相同格式。
对于 String
和 Regexp
(如下所述),特殊实例变量 :E
用于指示 Encoding
。
扩展¶ ↑
“e”表示下一个对象由模块扩展。对象紧随类型字节之后。对象之后是符号,其中包含扩展对象的模块的名称。
Array
¶ ↑
“[”表示 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
Class
和 Module
¶ ↑
“c”表示 Class
对象,“m”表示 Module
,而“M”表示类或模块(这是为了兼容性而保留的旧式用法)。不包含类或模块内容,此类型仅为引用。在类型字节之后是一个字节序列,分别用于查找现有的类或模块。
类或模块上不允许有实例变量。
如果不存在类或模块,则应引发异常。
对于“c”和“m”类型,加载的对象必须分别是类或模块。
Data
¶ ↑
“d”表示 Data
对象。(Data
对象是从 ruby 扩展中包装的指针。)在类型字节之后是一个符号,表示 Data
对象的类,以及一个包含 Data
对象状态的对象。
要转储 Data
对象,Ruby 会调用 _dump_data。要加载 Data
对象,Ruby 会在新建实例上使用对象的 state 调用 _load_data。
Float
¶ ↑
“f”表示 Float
对象。在类型字节之后是一个包含浮点值的字节序列。以下值是特殊的
- “inf”
-
正无穷大
- “-inf”
-
负无穷大
- “nan”
-
非数字
否则,字节序列包含一个 C double(可通过 strtod(3) 加载)。Marshal
的较旧次要版本还存储了额外的尾数位,以确保跨平台的可移植性,但 4.8 不包含这些位。请参见
- ruby-talk:69518
-
以获得一些说明。
Hash
和带默认值的 Hash
¶ ↑
“{” 表示 Hash
对象,而 “}” 表示设置了默认值(Hash.new 0
)的 Hash
。在类型字节之后是一个长整数,表示 Hash
中的键值对数量,即大小。给定的对象数量的两倍紧跟在大小之后。
对于带默认值的 Hash
,默认值紧跟在所有对之后。
Module
和旧 Module
¶ ↑
Object
¶ ↑
“o” 表示没有任何其他特殊形式(例如用户定义或内置格式)的对象。在类型字节之后是一个符号,其中包含对象的类名。在类名之后是一个长整数,表示对象的实例变量名称和值的数量。给定的对象对数量的两倍紧跟在大小之后。
对中的键必须是包含实例变量名称的符号。
正则表达式¶ ↑
“/” 表示正则表达式。在类型字节之后是一个字节序列,其中包含正则表达式源。在类型字节之后是一个字节,其中包含正则表达式选项(不区分大小写等)作为有符号 8 位值。
正则表达式可以通过实例变量附加编码(见上文)。如果没有附加编码,则必须删除 ruby 1.8 中不存在的以下正则表达式特殊字符的转义符:g-m、o-q、u、y、E、F、H-L、N-V、X、Y。
String
¶ ↑
‘“’ 表示 String
。在类型字节之后是一个字节序列,其中包含字符串内容。从 ruby 1.9 倾倒时,应包含编码实例变量(:E
,见上文),除非编码为二进制。
Struct
¶ ↑
“S” 表示 Struct
。在类型字节之后是一个符号,其中包含结构体的名称。在名称之后是一个长整数,表示结构体中的成员数量。成员数量的两倍紧跟在对象之后。每个成员都是一对,其中包含成员的符号和该成员值的对象。
如果结构体名称与正在运行的 ruby 中的 Struct
子类不匹配,则应引发异常。
如果当前运行的 Ruby 中的结构与已编组结构中的成员数量不匹配,则应引发异常。
用户 Class
¶ ↑
“C”表示 String
、Regexp
、Array
或 Hash
的子类。类型字节后是一个包含子类名称的符号。名称后是包装对象。
用户定义¶ ↑
“u”表示使用 _dump
实例方法和 _load
类方法的用户定义序列化格式的对象。类型字节后是一个包含类名称的符号。类名称后是一个包含对象的自定义表示的字节序列。
类方法 _load
在类上调用,并使用从字节序列创建的字符串。
用户 Marshal
¶ ↑
“U”表示使用 marshal_dump
和 marshal_load
实例方法的用户定义序列化格式的对象。类型字节后是一个包含类名称的符号。类名称后是一个包含数据的对象。
加载时必须分配一个新实例,并且必须使用数据在实例上调用 marshal_load
。