Ruby 2.4

Marshal

Marshal 模块

编组库将 Ruby 对象的集合转换为字节流,允许它们存储在当前活动脚本之外。随后可以读取该数据并重建原始对象。

封送的数据与对象信息一起存储有主版本号和次版本号。在正常使用中,封送处理只能加载使用相同主要版本号和等同或较低次要版本号编写的数据。如果设置了 Ruby 的“详细”标志(通常使用-d,-v,-w 或 -verbose),则主要和次要数字必须完全匹配。元帅版本控制独立于 Ruby 的版本号。您可以通过阅读编组数据的前两个字节来提取版本。

str = Marshal.dump("thing") RUBY_VERSION #=> "1.9.0" str[0].ord #=> 4 str[1].ord #=> 8

某些对象不能转储:如果要转储的对象包含绑定,过程或方法对象,类 IO 实例或单例对象,则会引发 TypeError。

如果您的类有特殊的序列化需求(例如,如果您想以某种特定格式序列化),或者如果它包含否则不可序列化的对象,则可以实现自己的序列化策略。

有两种方法可以做到这一点,你的对象可以定义 marshal_dump 和 marshal_load 或_dumpt和_load。如果两者都定义,marshal_dump 将优先于t_dump。marshal_dump 可能会导致较小的元帅字符串。

安全考虑

按照设计,:: load 可以反序列化几乎所有加载到 Ruby 进程中的类。在很多情况下,如果 Marshal 数据是从不可信源加载的,这可能会导致远程代码执行。

因此,:: load 不适合作为通用序列化格式,并且您不应该解组用户提供的输入或其他不可信数据。

如果您需要反序列化不可信数据,请使用tJSON或另一种只能加载简单的“原始”类型(例如tString,Array,Hash 等)的序列化格式。切勿允许用户输入指定要反序列化的任意类型。

marshal_dump and marshal_load

转储对象时,marshal_dump 方法将被调用。marshal_dump 必须返回包含 marshal_load 重构对象所需信息的结果。结果可以是任何对象。

当使用 marshal_dump 加载转储的对象时,首先分配对象,然后使用 marshal_dump 的结果调用 marshal_load。marshal_load 必须从结果中的信息中重新创建对象。

Example:

class MyObj def initialize name, version, data @name = name @version = version @data = data end def marshal_dump [@name, @version] end def marshal_load array @name, @version = array end end

_dump and _load

当你需要分配你正在恢复的对象时,使用 _dump 和 _load。

转储对象时,将使用 Integer 调用实例方法 _dump, Integer 指示要转储的对象的最大深度(值为-1意味着应禁用深度检查)。_dump 必须返回一个包含重构对象所需信息的 String。

类方法 _load 应该接受一个 String 并用它返回同一个类的对象。

例:

class MyObj def initialize name, version, data @name = name @version = version @data = data end def _dump level [@name, @version].join ':' end def self._load args new(*args.split(':')) end end

因为:: dump 会输出一个字符串,所以你可以让_dump 返回一个在 _load 中为 Marshal.loaded 的 Marshal 字符串作为复杂对象。

常量

MAJOR_VERSION

主要版本

MINOR_VERSION

次要版本

公共类方法

dump( obj , anIO , limit=-1 ) → anIO Show source

序列化 obj 和所有后代对象。如果指定了 anIO,则会将序列化的数据写入该数据,否则数据将以字符串形式返回。如果指定了限制,子对象的遍历将被限制在该深度。如果限制为负值,则不会执行深度检查。

class Klass def initialize(str) @str = str end def say_hello @str end end

(不产生输出)

o = Klass.new("hello\n") data = Marshal.dump(o) obj = Marshal.load(data) obj.say_hello #=> "hello\n"

Marshal 不能转储下列对象:

  • 匿名类/模块。

  • 与系统相关的对象(例如:Dir,File :: Stat,IO,File,Socket 等)

  • MatchData,Data,Method,UnboundMethod,Proc,Thread,ThreadGroup,Continuation 的一个实例

  • 定义单例方法的对象

static VALUE marshal_dump(int argc, VALUE *argv) { VALUE obj, port, a1, a2; int limit = -1; port = Qnil; rb_scan_args(argc, argv, "12", &obj, &a1, &a2 if (argc == 3) { if (!NIL_P(a2)) limit = NUM2INT(a2 if (NIL_P(a1)) io_needed( port = a1; } else if (argc == 2) { if (FIXNUM_P(a1)) limit = FIX2INT(a1 else if (NIL_P(a1)) io_needed( else port = a1; } return rb_marshal_dump_limited(obj, port, limit }

load( source , proc ) → obj Show source

返回将源代码中的序列化数据转换为 Ruby 对象(可能带有关联的从属对象)的结果。源可能是 IO 的一个实例或响应 to_str 的对象。如果指定了 proc,每个对象都将被传递给 proc,因为对象正在被反序列化。

切勿将不可信的数据(包括用户提供的输入)传递给此方法。请参阅概述了解更多详情。

static VALUE marshal_load(int argc, VALUE *argv) { VALUE port, proc; rb_check_arity(argc, 1, 2 port = argv[0]; proc = argc > 1 ? argv[1] : Qnil; return rb_marshal_load_with_proc(port, proc }

restore( source , proc ) → obj Show source

返回将源代码中的序列化数据转换为 Ruby 对象(可能带有关联的从属对象)的结果。源可能是IO 的一个实例或响应 to_str 的对象。如果指定了 proc,每个对象都将被传递给 proc,因为对象正在被反序列化。

切勿将不可信的数据(包括用户提供的输入)传递给此方法。请参阅概述了解更多详情。

static VALUE marshal_load(int argc, VALUE *argv) { VALUE port, proc; rb_check_arity(argc, 1, 2 port = argv[0]; proc = argc > 1 ? argv[1] : Qnil; return rb_marshal_load_with_proc(port, proc }