module Marshal:sig
..end
数据结构的序列化。
此模块提供函数,用于将任意数据结构编码为字节序列,然后可以将其写入文件或通过管道或网络连接发送。这些字节随后可以在以后读取,可能在另一个进程中,并解码回数据结构。字节序列的格式对于给定版本的 OCaml 在所有机器上都是兼容的。
警告:序列化目前不是类型安全的。序列化数据的类型不会与数据的值一起传输,因此无法检查读取回的数据是否具有上下文期望的类型。特别是,Marshal.from_*
函数的结果类型被给出为 'a
,但这具有误导性:返回的 OCaml 值并非对所有 'a
都有类型 'a
;它具有一个唯一的类型,该类型在编译时无法确定。程序员应该使用以下语法显式给出返回值的预期类型
(Marshal.from_channel chan : type)
。如果文件中的对象不属于给定类型,则在运行时可能会发生任何事情。可扩展变体类型的值,例如由反序列化程序返回的异常(可扩展类型 exn
),不应通过 match ... with
或 try ... with
进行模式匹配,因为反序列化不会保留匹配其构造函数所需的信息。与其他可扩展变体值的结构相等也不起作用。大多数其他用途,例如 Printexc.to_string,仍将按预期工作。
序列化值的表示形式不是人类可读的,并且使用不可打印字符的字节。因此,与 Marshal.to_channel
和 Marshal.from_channel
结合使用的输入和输出通道必须以二进制模式打开,例如使用 open_out_bin
或 open_in_bin
;在文本模式下打开的通道将在文本通道的行为与二进制通道不同的平台(例如 Windows)上导致反序列化错误。
type
extern_flags =
| |
No_sharing |
(* | 不保留共享 | *) |
| |
Closures |
(* | 发送函数闭包 | *) |
| |
Compat_32 |
(* | 确保 32 位兼容性 | *) |
以下 Marshal.to_*
函数的标志。
val to_channel : out_channel -> 'a -> extern_flags list -> unit
Marshal.to_channel chan v flags
将 v
的表示形式写入通道 chan
。 flags
参数是一个可能为空的标志列表,用于控制在共享、函数值以及 32 位和 64 位平台之间的兼容性方面进行序列化的行为。
如果 flags
不包含 Marshal.No_sharing
,则会检测并保留值 v
内部循环和共享在生成的字节序列中。特别是,这保证了序列化始终终止。连续调用 Marshal.to_channel
序列化的值之间的共享既不会被检测到也不会被保留。如果 flags
包含 Marshal.No_sharing
,则会忽略共享。如果 v
不包含共享的子结构,这将导致更快的序列化,但如果 v
实际上包含共享,或者甚至在 v
包含循环时,可能会导致更慢的序列化和更大的字节表示,甚至导致不终止。
如果 flags
不包含 Marshal.Closures
,则当序列化遇到 v
内部的函数值时会失败:只有“纯”数据结构(不包含函数或对象)才能安全地在不同的程序之间传输。如果 flags
包含 Marshal.Closures
,则函数值将被序列化为程序代码中的位置以及与闭包中捕获的自由变量相对应的值。在这种情况下,序列化的输出只能在运行完全相同的程序、具有完全相同的编译代码的进程中读取回。(这在反序列化时使用代码位置一起传输的代码的 MD5 摘要进行检查。)
闭包中捕获哪些自由变量的确切定义未指定,并且可能因字节码和本机代码(以及优化标志)而异。特别是,访问全局引用的函数值可能包含也可能不包含其闭包中的引用。如果包含,则反序列化相应的闭包将创建一个新的引用,与全局引用不同。
如果 flags
包含 Marshal.Compat_32
,则当序列化遇到在 32 位平台上可表示的整数范围 -2
30
, 2
30
-1
之外的整数值时会失败。这确保了在 64 位平台上生成的数据可以在 32 位平台上安全地读回。如果 flags
不包含 Marshal.Compat_32
,则会序列化范围 -2
30
, 2
30
-1
之外的整数值,并且可以在 64 位平台上读回,但在 32 位平台上读回时会导致反序列化时出错。Mashal.Compat_32
标志仅在 64 位平台上执行序列化时才重要;如果在 32 位平台上执行序列化,则它没有效果。
Failure
,如果 chan
不是二进制模式。val to_bytes : 'a -> extern_flags list -> bytes
Marshal.to_bytes v flags
返回包含 v
表示形式的字节序列。 flags
参数与 Marshal.to_channel
的含义相同。
val to_string : 'a -> extern_flags list -> string
与 to_bytes
相同,但将结果作为字符串而不是字节序列返回。
val to_buffer : bytes -> int -> int -> 'a -> extern_flags list -> int
Marshal.to_buffer buff ofs len v flags
序列化值 v
,将其字节表示存储在序列 buff
中,从索引 ofs
开始,最多写入 len
个字节。它返回实际写入序列的字节数。如果 v
的字节表示形式不适合 len
个字符,则会引发异常 Failure
。
val from_channel : in_channel -> 'a
Marshal.from_channel chan
从通道 chan
读取结构化值的字节表示形式,如 Marshal.to_*
函数之一生成的,并重建并返回相应的值。
End_of_file
,如果 chan
已经位于文件的末尾。Failure
,如果在反序列化本身期间到达文件末尾或 chan
不是二进制模式。val from_bytes : bytes -> int -> 'a
Marshal.from_bytes buff ofs
反序列化结构化值,类似于 Marshal.from_channel
所做的那样,只是字节表示形式不是从通道读取的,而是从字节序列 buff
中获取的,从位置 ofs
开始。字节序列不会发生变异。
val from_string : string -> int -> 'a
与 from_bytes
相同,但将字符串作为参数而不是字节序列。
val header_size : int
表示序列化值的字节由一个固定大小的头部和一个可变大小的数据部分组成,其大小可以从头部确定。Marshal.header_size
是头部的字节大小。Marshal.data_size
buff ofs
是数据部分的字节大小,假设有效的头部存储在从位置 ofs
开始的 buff
中。最后,Marshal.total_size
buff ofs
是序列化值的总字节大小。Marshal.data_size
和 Marshal.total_size
都会在 buff
, ofs
不包含有效头部时引发 Failure
。
要将序列化值的字节表示形式读入字节序列,程序需要先将 Marshal.header_size
个字节读入序列,然后使用 Marshal.data_size
确定表示形式其余部分的长度,确保序列足够大以容纳剩余的数据,然后读取它,最后调用 Marshal.from_bytes
来反序列化该值。
val data_size : bytes -> int -> int
val total_size : bytes -> int -> int
在序列化可能被不同域修改的可变值时必须小心。修改正在序列化的值(即,转换为字节序列)是一个编程错误,并且由于撕裂,可能会导致令人惊讶的值(在反序列化时),因为序列化涉及逐字节复制。