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
}