如何将任意的 Ruby 对象保存到磁盘并在需要时读取?

8

我想将一个Ruby set或hash保存到磁盘上,并在需要时从文件中恢复它们。我该如何实现这个功能?


3
如果一个旧问题不再符合主题,则我们可以关闭它,同样地,如果关闭原因已经不再适用,我们也可以重新打开一个旧问题。这是一个公正的问题,已经产生了好的答案,因此我投票支持重新打开。 - Wayne Conrad
2个回答

8

Marshal模块可以将一个对象转化为字符串并写入文件。读取文件并使用Marshal.load方法即可还原该对象。

Marshal.dump方法接受一个可选参数'anIO',通常指向一个文件。

h = { "hi" => 1}
# dumping:
File.open("test.marshal", "w"){|to_file| Marshal.dump(h, to_file)}
# retrieving:
p File.open("test.marshal", "r"){|from_file| Marshal.load(from_file)} #=> {"hi"=>1}

注意事项

Marshal.dump创建的文件格式可能会因不同的Ruby版本或实现而改变。如果您需要创建任何版本的Ruby都可以读取的文件,请使用类似YAML或JSON的东西,而不是使用Marshal.dump。

有些对象无法被序列化(也就是说,无法使用Marhsal.dump进行转储)。Lambda和proc是其中之一,因此如果您的哈希表具有其default_proc属性设置,则无法对该哈希表进行转储。为了解决这个问题,您可以在保存之前将default_proc设置为nil(例如: my_hash.default_proc = nil),但是在加载哈希表后,您需要重新设置default_proc到正确的值。


8

一个Set基本上就是一个哈希表,每个键/值对的值都设置为相同的值。正是键使其像一个集合。

一旦我们知道了这一点,保存和恢复Set就像保存数组或哈希表一样,可以通过多种方式完成。

@steenslag提到了使用Marshall.dump,这是很好的方法。

由于Set是Hash的变体,因此您还可以使用YAMLJSON来序列化数据。它们的最大优点是易于在其他语言中重用。YAML和JSON通常用于在主机之间存储和传输数据,并且格式非常易读。

以下是一些示例,以便给您一些想法:

require 'set'
require 'json'
require 'yaml'

foo = Set.new
foo << 1
foo << 2
foo << 1
foo # => #<Set: {1, 2}>

foo 是一个集合。它也可以转换为数组:

foo.to_a # => [1, 2]

我们可以使用YAML来序列化Set:

puts YAML.dump(foo)
# >> --- !ruby/object:Set
# >> hash:
# >>   1: true
# >>   2: true

同时,我们可以创建序列化版本,然后将其解析回Set:

YAML.load(YAML.dump(foo)) # => #<Set: {1, 2}>

由于 foo 是一个 Set,我们也可以将其转换为一个数组,然后使用 YAML 序列化它:

puts YAML.dump(foo.to_a)
# >> ---
# >> - 1
# >> - 2  

然后我们可以读取数据,如果需要的话,将其转换回Set:
bar = YAML.load(YAML.dump(foo.to_a)).to_set
bar.class # => Set
bar # => #<Set: {1, 2}>

或者,如果是读取YAML的语言不支持Set,比如Perl,那么当Perl代码读取和解析数据时,它可以保留为Array。
JSON的工作方式类似。以下是通过Array传输数据的往返示例:
foo.to_a.to_json # => "[1,2]"
JSON.parse(foo.to_a.to_json) # => [1, 2]
JSON.parse(foo.to_a.to_json).to_set # => #<Set: {1, 2}>

JSON还具有[]方法,该方法足够智能,可以确定传递的参数是String、Array还是Hash。如果是第一个,则解析该参数并作为Ruby对象返回。如果是后两个,则序列化并转换为字符串:

JSON[foo.to_a] # => "[1,2]"
JSON[JSON[foo.to_a]] # => [1, 2]
JSON[JSON[foo.to_a]].to_set # => #<Set: {1, 2}>

无论使用JSON还是YAML,读写生成的字符串都可以使用几种不同的IO或File方法轻松完成。请查看File.writeFile.read,这两个方法都继承自IO类,如果您决定使用YAML,请查看YAML.load_file,它继承自Psych类

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接