【发布时间】:2013-11-30 04:52:30
【问题描述】:
我想将 Ruby 集或哈希保存到磁盘,并在必要时从文件中返回。我该怎么做?
【问题讨论】:
-
如果我们可以关闭一个旧问题,因为它不再是主题,那么我们可以重新打开一个旧问题,因为它关闭的原因不再有效。这是一个公平的问题,已经产生了很好的答案,所以投票重新开放。
标签: ruby file object save disk
我想将 Ruby 集或哈希保存到磁盘,并在必要时从文件中返回。我该怎么做?
【问题讨论】:
标签: ruby file object save disk
集合基本上是一个散列,每个键/值对的值设置为相同的值。这是使它表现得像一个集合的关键。
一旦我们知道,保存和恢复 Set 就像保存 Array 或 Hash,并且可以通过多种方式完成。
@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,我们也可以把它转成一个Array,然后用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.write 和File.read,它们都继承自IO,如果您决定使用YAML,请查看YAML.load_file, which is inherited from Psych。
【讨论】:
Marshal 模块以字符串形式转储对象,可以将其写入文件。读取文件并Marshal.load'ing 字符串给出原始对象。
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 转储)。 Lambdas 和 procs 属于这些对象,因此如果您的哈希设置了其default_proc 属性,那么您将无法编组该哈希。要解决此问题,您可以在保存之前将 default_proc 设置为 nil(例如 my_hash.default_proc = nil),但您需要在加载哈希后将 default_proc 重置为正确的值。
【讨论】: