模块 Stdlib.Marshal

module Marshal: Marshal

type extern_flags = 
| No_sharing (*

不保留共享

*)
| 闭包 (*

发送函数闭包

*)
| Compat_32 (*

确保 32 位兼容性

*)

下面 Marshal.to_* 函数的标志。

val to_channel : out_channel -> 'a -> extern_flags list -> unit

Marshal.to_channel chan v flagsv 的表示形式写入通道 chanflags 参数是一个可能为空的标志列表,用于控制关于共享、函数值以及 32 位和 64 位平台之间兼容性的编组行为。

如果 flags 不包含 Marshal.No_sharing,则会检测值 v 内部的循环和共享,并在生成的字节序列中保留这些信息。特别是,这保证了编组始终会终止。连续调用 Marshal.to_channel 编组的值之间的共享既不会被检测到,也不会被保留。如果 flags 包含 Marshal.No_sharing,则会忽略共享。如果 v 不包含共享的子结构,这将导致更快的编组,但如果 v 实际上包含共享,或者甚至包含循环,则可能会导致编组速度变慢和字节表示形式更大,甚至导致不终止。

如果 flags 不包含 Marshal.Closures,则在遇到 v 内部的函数值时,编组将失败:只有“纯”数据结构(不包含函数或对象)才能安全地在不同程序之间传输。如果 flags 包含 Marshal.Closures,则函数值将被编组为程序代码中的位置以及对应于闭包中捕获的自由变量的值。在这种情况下,编组的输出只能在运行完全相同程序且编译代码完全相同的进程中读取。(这在解编组时使用代码位置一起传输的代码的 MD5 摘要进行检查。)

闭包中捕获哪些自由变量的精确定义未指定,并且在字节码和原生代码之间可能有所不同(并根据优化标志)。特别是,访问全局引用的函数值可能包含也可能不包含其闭包中的引用。如果包含,则解编组相应的闭包将创建一个新的引用,该引用与全局引用不同。

如果 flags 包含 Marshal.Compat_32,则在遇到超出 32 位平台上可表示的整数范围 -230, 230-1 的整数值时,编组将失败。这确保了在 64 位平台上生成的数据可以安全地在 32 位平台上读回。如果 flags 不包含 Marshal.Compat_32,则会编组超出范围 -230, 230-1 的整数值,并且可以在 64 位平台上读回,但在 32 位平台上读回时会在解编组时导致错误。 Mashal.Compat_32 标志仅在 64 位平台上执行编组时才重要;如果在 32 位平台上执行编组,则它没有任何作用。

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_* 函数生成),并重建并返回相应的值。

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 是编组值的总字节大小。如果 buff, ofs 不包含有效的头部,则 Marshal.data_sizeMarshal.total_size 都将引发 Failure

要将编组值的字节表示形式读入字节序列,程序需要首先将 Marshal.header_size 个字节读入序列,然后使用 Marshal.data_size 确定表示形式其余部分的长度,确保序列足够大以容纳剩余数据,然后读取它,最后调用 Marshal.from_bytes 来解编组该值。

val data_size : bytes -> int -> int
val total_size : bytes -> int -> int

Marshal 和域安全

在编组可能被不同域修改的可变值时必须小心。修改正在编组的值(即转换为字节序列)是一个编程错误,并且由于撕裂,可能会导致意外的值(在解编组时),因为编组涉及逐字节复制。