Marshal
格式¶ ↑
Marshal
格式用於序列化 Ruby 物件。此格式可透過三種使用者定義的延伸機制儲存任意物件。
有關使用 Marshal
序列化和取消序列化物件的文件,請參閱 Marshal
模組。
本文件將一組序列化的物件稱為串流。Ruby 實作可以從 String
、IO
或實作 getc
方法的物件載入一組物件。
串流格式¶ ↑
串流的前兩個位元組包含主版本和次要版本,每個位元組編碼一個數字。Ruby 中實作的版本為 4.8(儲存為「x04x08」),並受 ruby 1.8.0 及更新版本支援。
Marshal
格式的不同主版本不相容,且無法由其他主版本理解。格式的較低次要版本可以由較新的次要版本理解。格式 4.7 可以由 4.8 實作載入,但格式 4.8 無法由 4.7 實作載入。
在版本位元組之後,是一個描述序列化物件的串流。串流包含巢狀物件(與 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 和 Symbols 除外(如上所述,這些物件會另外儲存),當再次遇到物件時,會儲存和重複使用一個從 1 開始編號的 32 位元值。(第一個物件的索引為 1)。
「@」代表物件連結。在類型位元組之後,會有一個長整數提供物件的索引。
例如,以下串流包含一個 Array
,其中包含同一個 "hello"
物件兩次
"\004\b[\a\"\nhello@\006"
執行個體變數¶ ↑
「I」表示執行個體變數會在下一物件之後。一個物件會在類型位元組之後。在物件之後,會有一個長度,表示物件的執行個體變數數量。在長度之後,會有一組名稱-值對。名稱是符號,而值是物件。符號必須是執行個體變數名稱(:@name
)。
一個 Object
(「o」類型,如下所述)會使用與這裡所述相同的格式,作為其執行個體變數。
對於 String
和 Regexp
(如下所述),會使用一個特殊的執行個體變數 :E
來表示 Encoding
。
延伸¶ ↑
「e」表示下一個物件會由模組延伸。一個物件會在類型位元組之後。在物件之後,會有一個符號,其中包含物件延伸的模組名稱。
Array
¶ ↑
「[」代表一個 Array
。在類型位元組之後,會有一個長整數,表示陣列中的物件數量。指定數量的物件會在長度之後。
Bignum¶ ↑
「l」代表一個 Bignum,它由三部分組成
- 符號
-
一個單一位元組,包含正值的「+」或負值的「-」。
- 長度
-
一個長度表示 Bignum 資料的位元組數,除以二。將長度乘以二,以確定後續資料的位元組數。
- 資料
-
表示數字的 Bignum 資料位元組。
下列 Ruby 程式碼將從位元組陣列重建 Bignum 值
result = 0 bytes.each_with_index do |byte, exp| result += (byte * 2 ** (exp * 8)) end
類別
和 模組
¶ ↑
“c” 表示 類別
物件,“m” 表示 模組
,“M” 表示類別或模組(這是為了相容性而使用的舊式格式)。不包含類別或模組內容,此類型只是一個參考。在類型位元組之後,會有一個位元組序列,分別用於查詢現有的類別或模組。
類別或模組不允許有實例變數。
如果不存在類別或模組,則應引發例外狀況。
對於“c”和“m”類型,載入的物件必須分別是類別或模組。
資料
¶ ↑
“d” 表示 資料
物件。(資料
物件是 Ruby 延伸模組的封裝指標。)在類型位元組之後,會有一個符號表示 資料
物件的類別,以及一個包含 資料
物件狀態的物件。
若要傾印 資料
物件,Ruby 會呼叫 _dump_data。若要載入 資料
物件,Ruby 會在一個新配置的實例上呼叫 _load_data,並傳入物件的狀態。
浮點數
¶ ↑
“f” 表示 浮點數
物件。在類型位元組之後,會有一個位元組序列,其中包含浮點數值。下列值是特殊的
- “inf”
-
正無限大
- “-inf”
-
負無限大
- “nan”
-
非數字
否則,位元組序列包含一個 C double(可由 strtod(3) 載入)。較舊的 Marshal
次要版本也儲存了額外的尾數位元,以確保跨平台的可攜性,但 4.8 不包含這些位元。請參閱
- ruby-talk:69518
-
以取得一些說明。
雜湊
和具有預設值的 雜湊
¶ ↑
“{” 表示 雜湊
物件,而 “}” 表示具有預設值設定的 雜湊
(Hash.new 0
)。在類型位元組之後,會有一個長度表示 雜湊
中的鍵值對數量,即大小。物件的給定數量兩倍會出現在大小之後。
對於具有預設值的 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
,並使用資料。