如何将任意 Ruby 对象保存到磁盘并在必要时将其读回? [关闭]

Posted

技术标签:

【中文标题】如何将任意 Ruby 对象保存到磁盘并在必要时将其读回? [关闭]【英文标题】:How can I save an arbitrary Ruby object to the disk and read it back when necessary? [closed] 【发布时间】:2013-11-30 04:52:30 【问题描述】:

我想将 Ruby 集或哈希保存到磁盘,并在必要时从文件中返回。我该怎么做?

【问题讨论】:

如果我们可以关闭一个旧问题,因为它不再是主题,那么我们可以重新打开一个旧问题,因为它关闭的原因不再有效。这是一个公平的问题,已经产生了很好的答案,所以投票重新开放。 【参考方案1】:

集合基本上是一个散列,每个键/值对的值设置为相同的值。这是使它表现得像一个集合的关键。

一旦我们知道,保存和恢复 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。

【讨论】:

【参考方案2】:

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 重置为正确的值。

【讨论】:

以上是关于如何将任意 Ruby 对象保存到磁盘并在必要时将其读回? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Ruby 将数据保存到 JSON 中并在以后使用?

如何访问 Hololens 3D 对象文件夹中的文件并在运行时将其发送到应用程序

如何将 UIView 锚定到屏幕上的特定位置并在滚动时将其保留在那里

如何从 zip 中提取 csv 文件并在 python 中将其保存到磁盘? [复制]

从 C# 启动 Excel 并在“保存”时将其关闭

每当我单击一个开关时,我都需要创建一个新对象,并在关闭时将其删除