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处理CSV数据方法详解
Apr 18 Ruby
Ruby处理YAML和json数据
Apr 18 Ruby
Ruby序列化和持久化存储 Marshal和Pstore介绍
Apr 18 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代码
2011/11/27 PHP
采用header定义为文件然后readfile下载(隐藏下载地址)
2014/01/31 PHP
PHP防止图片盗用(盗链)的方法小结
2016/11/11 PHP
用PHP将Unicode 转化为UTF-8的实现方法(推荐)
2017/02/08 PHP
php中类和对象:静态属性、静态方法
2017/04/09 PHP
laravel 解决多库下的DB::transaction()事务失效问题
2019/10/21 PHP
php接口隔离原则实例分析
2019/11/11 PHP
javascript检测页面是否缩放的小例子
2013/05/16 Javascript
页面加载完毕后滚动条自动滚动一定位置
2014/02/20 Javascript
类似天猫商品详情随浏览器移动的示例代码
2014/02/27 Javascript
本人自用的global.js库源码分享
2015/02/28 Javascript
使用C++为node.js写扩展模块
2015/04/22 Javascript
Javascript BOM学习小结(六)
2015/11/26 Javascript
JavaScript截取、切割字符串的技巧
2016/01/07 Javascript
jQuery ajaxSubmit 实现ajax提交表单局部刷新
2016/07/04 Javascript
浅谈原生JS实现jQuery的animate()动画示例
2017/03/08 Javascript
推荐VSCode 上特别好用的 Vue 插件之vetur
2017/09/14 Javascript
vue中选项卡点击切换且能滑动切换功能的实现代码
2018/11/25 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
2019/06/10 Javascript
vue 实现移动端键盘搜索事件监听
2019/11/06 Javascript
[01:18:35]DOTA2-DPC中国联赛 正赛 Elephant vs LBZS BO3 第一场 1月29日
2021/03/11 DOTA
Python中使用PyHook监听鼠标和键盘事件实例
2014/07/18 Python
获取python文件扩展名和文件名方法
2018/02/02 Python
Python实现随机生成手机号及正则验证手机号的方法
2018/04/25 Python
Python中logging实例讲解
2019/01/17 Python
python3 requests库文件上传与下载实现详解
2019/08/22 Python
Python绘图之柱形图绘制详解
2020/07/28 Python
用CSS3的box-reflect来制作倒影效果
2016/11/15 HTML / CSS
详解HTML5之pushstate、popstate操作history,无刷新改变当前url
2017/03/15 HTML / CSS
衰败城市英国官网:Urban Decay英国
2020/04/29 全球购物
艺术专业大学生自我评价
2013/09/22 职场文书
《浅水洼里的小鱼》听课反思
2014/02/28 职场文书
检举信的格式及范文
2014/04/04 职场文书
2014年安全生产目标责任书
2014/07/23 职场文书
作风整顿个人剖析材料
2014/10/06 职场文书
高中生期中考试失利检讨书
2014/10/23 职场文书