我想将一个Ruby set或hash保存到磁盘上,并在需要时从文件中恢复它们。我该如何实现这个功能?
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
到正确的值。
一个Set基本上就是一个哈希表,每个键/值对的值都设置为相同的值。正是键使其像一个集合。
一旦我们知道了这一点,保存和恢复Set就像保存数组或哈希表一样,可以通过多种方式完成。
@steenslag提到了使用Marshall.dump
,这是很好的方法。
由于Set是Hash的变体,因此您还可以使用YAML或JSON来序列化数据。它们的最大优点是易于在其他语言中重用。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
bar = YAML.load(YAML.dump(foo.to_a)).to_set
bar.class # => Set
bar # => #<Set: {1, 2}>
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}>
YAML.load_file
,它继承自Psych类。