Ruby序列化和持久化存储 Marshal和Pstore介绍


Posted in Ruby onApril 18, 2022

Ruby Marshal序列化

Marshal是Ruby的核心库,可以将一些对象以二进制的方式序列化保存到文件中,需要时再从文件中加载重新构建成对象,即反序列化。

Marshal对数值、字符串、数组、布尔值等基础数据的序列化保存没有任何问题。

但并非所有类型的数据都能序列化。Marshal从序列化文件中加载并重新构建成对象的过程中会执行一些操作,但还原的过程有些内容可能会丢失它不能序列化I0流对象以及代码类对象: Proc对象、 单例对象、匿名类和模块,这是它的限制所在。

序列化和反序列化的过程非常简单:

# 一个嵌套数组
arr = [
  %w(Perl Python PHP),
  %w(C C++ Java Golang),
  %w(Shell Powershell Cmdline)
  ]

# 将arr对象序列化保存到文件中
File.open('/tmp/data.dat', "w") do |file|
  Marshal.dump(arr, file)
end

# 反序列化
File.open('/tmp/data.dat') do |file|
  data = Marshal.load(file)
end

p data

Marshal.dump()还可以通过第三个参数指定最多允许序列化多少个嵌套的对象层次,即深度,超出了深度将报错。其默认值为-1,此时表示不检查深度,即dump所有层次。例如:

arr = [
  %w(Perl Python PHP),
  [ %w(C C++), %(Java Golang) ],   #=> 3层
  %w(Shell Powershell Cmdline)
  ]

# 将arr对象序列化保存到文件中
File.open('/tmp/data.dat', "w") do |file|
  Marshal.dump(arr, file, 4)      #=> 小于4将报错
end

如果想要指定对象中要序列化的内容,或者指定序列化成什么类型,可以在类中编写marshal_dumpmarshal_load方法。例如,只dump一部分数据并以数组的方式保存:

class Klass
  def initialize name, age, height 
    @name = name
    @age = age
    @height = height
  end
  
  def marshal_dump
    [@name, @age]
  end
  
  # 反序列化,arr是序列化时的数组
  # 最终它返回一个Klass的实例对象
  def marshal_load arr
    @name, @age = arr
  end
end

# 序列化Klass的一个对象,但只会包含name和age两个属性
obj = Klass.new("junmajinlong", 23, 170)
File.open('/tmp/me.dat','w') do |file|
  Marshal.dump(obj, file)
end

# 反序列化,得到一个Klass的实例对象,并设置name和age属性
obj1 = File.open("/tmp/me.dat") do |file|
  Marshal.load file
end

p obj1
#=> #<Klass:0x00007fffcc0119f8 @name="junmajinlong", @age=23>

显然,上面反序列化的过程中缺少了一个height属性。为了让对象完整,在反序列化的时候需要根据反序列化得到的结果合理构建新对象。例如,使用instance_eval()构建新对象:

def marshal_load arr
  self.instance_eval do
    initialize(*arr, 170)
  end
end

Ruby Pstore存储

Pstore(persistence store)是Ruby的一个持久化存储的标准库,它以基于Hash数据类型的方式将数据以key-value的方式存储在文件中(二进制的),其中value是想要存储的数据,key是这部分数据的一个名称。

在Pstore中,key称为root,每个key都是一个root。

Pstore是基于事务的,所以多次增删改数据的过程是原子的,可统一提交(commit)、统一回滚(abort)。commit()和abort()时都会立即终止本次事务,所以它们后面的代码不会执行,如果没有指定commit()或abort(),则在退出transaction的时候自动保存。

因为pstore每次读都要先加载文件部分内容到内存(直到找到对应的key),所以读效率不高。再者,每次写入都需要拷贝文件的绝大部分数据,所以效率更低。因此,Pstore只适用于少量数据、少量读写的数据存储场景。

例如,持久化保存到文件:

require 'pstore'

s = PStore.new('/tmp/pstore.dat')

s.transaction do
  s["p1"] = {name: "junmajinlong", age: 23, height: 170 }
  s["p2"] = {name: "junma", age: 22, height: 180}
  s.commit
  s["p3"] = {name: "jinlong", age: 24}
end

s.transaction do
  # 覆盖p2
  s["p2"] = {name: "jinlong", age: 24, height: 170 } 
end   #=> 自动commit

从pstore文件中读取数据:

require 'pstore'

s = PStore.new("/tmp/pstore.dat")

p2 = s.transaction do
  s["p2"]
end
p p2
puts p2.name

transaction(read_only=false)还可以指定参数设置该事务是否只读,如果设置了只读,则事务内对pstore做任何修改都会抛出错误。

Pstore还有其它一些辅助方法:

[KEY]     :获取元素的值,如果元素不存在则返回nil
delete()  :删除元素,可指定元素不存在时的默认值参数
fetch()   :获取元素,如果元素不存在,默认报错,可指定默认返回值  
path()    :返回pstore文件的路径
root?()   :检查key是否存在  
roots()   :返回所有的key
Ruby 相关文章推荐
Ruby序列化和持久化存储 Marshal和Pstore介绍
Apr 18 Ruby
Ruby使用Mysql2连接操作MySQL
Apr 19 Ruby
Ruby GDBM操作简介及数据存储原理
Apr 19 Ruby
安装Ruby和 Rails的详细步骤
Apr 19 Ruby
Python如何将list中的string转换为int
Jul 15 Ruby
Ruby处理CSV数据方法详解
Apr 18 #Ruby
Ruby处理YAML和json数据
Apr 18 #Ruby
Ruby使用Mysql2连接操作MySQL
Apr 19 #Ruby
Ruby GDBM操作简介及数据存储原理
Apr 19 #Ruby
安装Ruby和 Rails的详细步骤
Python如何将list中的string转换为int
Jul 15 #Ruby
You might like
php 应用程序安全防范技术研究
2009/09/25 PHP
yiic命令时提示“php.exe”不是内部或外部命令的解决方法
2014/12/18 PHP
thinkphp在php7环境下提示Cannot use ‘String’ as class name as it is reserved的解决方法
2016/09/30 PHP
PHP中overload与override的区别
2017/02/13 PHP
JavaScript入门教程(8) Location地址对象
2009/01/31 Javascript
jQuery选择头像并实时显示的代码
2010/06/27 Javascript
jquery load()在firefox(火狐)下显示不正常的解决方法
2011/04/05 Javascript
使用Jquery打造最佳用户体验的登录页面的实现代码
2011/07/08 Javascript
再谈javascript面向对象编程
2012/03/18 Javascript
extjs 04_grid 单击事件新发现
2012/11/27 Javascript
jQuery对象和Javascript对象之间转换的实例代码
2013/03/20 Javascript
javascript根据时间生成m位随机数最大13位
2014/10/30 Javascript
JavaScript跨浏览器获取页面中相同class节点的方法
2015/03/03 Javascript
AngularJS开发教程之控制器之间的通信方法分析
2016/12/25 Javascript
jQuery Ajax 实现在html页面实时显示用户登录状态
2016/12/30 Javascript
提高JavaScript执行效率的23个实用技巧
2017/03/01 Javascript
利用imgareaselect辅助后台实现图片上传裁剪
2017/03/02 Javascript
javascript DOM的详解及实例代码
2017/03/06 Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
2017/08/23 Javascript
ubuntu编译nodejs所需的软件并安装
2017/09/12 NodeJs
vue项目中使用lib-flexible解决移动端适配的问题解决
2018/08/23 Javascript
详解ES6系列之私有变量的实现
2018/11/21 Javascript
JavaScript JSON数据处理全集(小结)
2019/08/15 Javascript
layui点击数据表格添加或删除一行的例子
2019/09/12 Javascript
Python使用剪切板的方法
2017/06/06 Python
python traceback捕获并打印异常的方法
2018/08/31 Python
Django Rest framework认证组件详细用法
2019/07/25 Python
python递归下载文件夹下所有文件
2019/08/31 Python
Numpy一维线性插值函数的用法
2020/04/22 Python
Pycharm常用快捷键总结及配置方法
2020/11/14 Python
Melissa鞋英国官方网站:Nonnon
2019/05/01 全球购物
护士找工作求职信
2014/07/02 职场文书
篮球赛新闻稿
2015/07/17 职场文书
中学政教处工作总结
2015/08/13 职场文书
PyTorch 实现L2正则化以及Dropout的操作
2021/05/27 Python
Python必备技巧之函数的使用详解
2022/04/04 Python