ruby 序列化和YAML

序列化的概念

序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将数据流转换为对象。这两个过程结合起来,就使得数据能够被轻松地存储和传输。

为什么需使用序列化?有两个重要的原因:一个原因是将对象的状态保存在存储介质中,以便在以后重新创建精确的副本;另一个原因是可以将对象从一个应用程序发送到另一个应用程序中,远程处理还可以使用序列化将对象从一台机器上的应用程序传递到另一台机器上的应用程序中。

一般程序在运行时产生对象,这些对象随着程序的停止运行而消失,我们可以通过序列化将对象保存下来,这样在程序终止运行后这些对象仍然存在。以后可以在程序再次运行时通过读取数据重建这些对象,也可以在在其他程序中利用这些保存下来的对象。这种情况下我们通过使用对象的序列化和反序列化来完成这样的功能。

  使用序列化   二进制数据保存

在 Ruby 中,序列化也称为 marshaling ,使用 Marshal 类 R 可以把一个对象转换成字节流,并把它存在应用程序外。这样保存的对象可以在以后被其它的实例或者其它的程序读取使用。

可以使用 Marshal 类的 dump 方法保存对象,以后使用 load 可以读取以保存的这个对象。  

class Rectangle

       def initialize(length, width)

           @length= length

           @width = width

           @area = length * width

       end 

      def to_s

           "#@length #@width #@area"

       end

end 

obj = Rectangle.new(10,20)

puts "Before: obj = #{obj}"

data = Marshal.dump(obj)

obj = Marshal.load(data)

puts "After: obj = #{obj}"

puts obj.inspect 

执行结果为:

Before: obj = 10 20 200

After: obj = 10 20 200

#<Rectangle:0x2ac 7928 @length=10, @area=200, @width=20>

YAML 数据保存

我们也可以使用 YAML 来实现序列化:

require 'yaml' 

class Rectangle

       def initialize(length, width)

           @length= length

           @width = width

           @area = length * width

       end 

        def to_s

           "#@length #@width #@area"

       end

end 

obj = Rectangle.new(10,20)

puts "Before: obj = #{obj}"

data = YAML.dump(obj)

obj = YAML.load(data)

puts "After: obj = #{obj}"

puts obj.inspect 

执行结果为:

Before: obj = 10 20 200

After: obj = 10 20 200

#<Rectangle:0x2ebbe08 @length=10, @area=200, @width=20>

定制序列化   二进制数据保存

并不是所有的数据都可以被序列化和适合序列化,有时候你想自己决定哪些东西被序列化, Marshal 类提供了二个方法来实现这样的功能,一个是 marshal_dump ,一个是 marshal_load 。当使用 Marshal.load 对一个对象进行序列化的时候,如果这个对象定义了 marshal_dump 或 marshal_load 方法,那么这个方法将会被调用。

class Rectangle

        def initialize(length, width)

           @length= length

           @width = width

           @area = length * width

        end 

        def marshal_dump

           [ @length, @width ]

        end

        def marshal_load(variables)

           @length = variables[0]

           @width = variables[1]

           @area = "unknown"

        end

        def to_s

           "#@length #@width #@area"

       end

end 

obj = Rectangle.new(10, 20)

puts "Before: obj = #{obj}"

data = Marshal.dump(obj)

obj = Marshal.load(data)

puts "After: obj = #{obj}" 

执行结果为:

Before: obj = 10 20 200

After: obj = 10 20 unknown 

一些对象不能被保存,如果将要被保存的对象包括其它程序调用,方法体, IO 实例等,或者单独的一个对象,或者当你保存一个匿名的类或者方法时,一个 TypeError 错误就会产生。

  YAML 数据保存

使用 Marshal 模块实现序列化将对象保存为二进制数据,这样的做法有一个显著的缺点,由于保存的数据是二进制形式,如果解释器发生了重大改变且 Marshal 的二进制数据流处理格式和方式也发生了变化,那么就不保证原有已经 dump 的文件还可以继续使用。

如果使用文本格式的文件来保存序列化数据,那么就不用担心文件是否可读,在 Ruby1.8 种,可以使用 YAML 来实现这样的功能。

对于 marshaling ,除了二进制格式,也可以采用 YAML 的方法,它是一种纯文字又易懂的格式,很有趣而且比起 XML 简单多了。  

修改一下上一节的例子,我们需要定义 to_yaml_properties 方法,  

require 'yaml' 

class Rectangle

        def initialize(length, width)

           @length= length

           @width = width

           @area = length * width

        end 

        def to_yaml_properties

           %w{ @length @width }

       end 

        def to_s

           "#@length #@width #@area"

       end

end 

obj = Rectangle.new(10,20)

puts "Before: obj = #{obj}"

data = YAML.dump(obj)

obj = YAML.load(data)

puts "After: obj = #{obj}" 

执行结果为:

Before: obj = 10 20 200

After: obj = 10 20  

我们可以看看 YAML 究竟把数据保存成什么样的格式,

obj = Rectangle.new(10,20)

puts YAML.dump(obj) 

执行结果为 :

-- !ruby/object:Rectangle

length: 10

width: 20  

看了上一节,大家或许会问,“为什么要命名为 YAML ?”已经有许多工具采用了招人喜欢的“ YA* ”形式的首字母缩略词,来表示“还有另一种 XXX ( Yet Another XXX )”。在开放源码这个充满智慧的领域中, YAML 没有使用其名称所暗示的首字母缩略词,而是采用了循环的“ YAML 不是标记语言( YAML Ain't Markup Language )”的缩写。然而对此产生的某种感觉是: YAML 确实可以做标记语言所做的工作,却不需要任何标记。

尽管 YAML 与 XML 一样普通,但在阅读、编辑、修改和产生方面,它比 XML 简单得多。可以用 XML 表示的任何东西,都可以用 YAML 表示,而且几乎总是更紧凑。

XML 是一个典型的由委员会驱动的庞然大物,它试图成为一种文档格式、数据格式、消息包格式、安全的 RPC 通道( SOAP )以及一种对象数据库。而且, XML 为每一类型的访问和操作都提供了大量的 API : DOM 、 SAX 、 XSLT 、 XPATH 、 JDOM 以及许多不太常见的接口层。非常了不起的是 XML 完成了所有这些工作;令人失望的是没有一项工作是完美无缺的。

YAML 的关注面则比较窄,它只是清晰地表示在动态编程语言(如 Perl 、 Python 、 Ruby 等)中所遇到的数据结构以及数据类型。

YAML 的优点:

 适合人们阅读

适合与脚本语言交流

使用宿主语言的内部数据结构

拥有一致性的信息模型

使基于流式数据的处理成为可能

富于表达和可扩展

容易实现

YAML 做为一个可移植的对象序列化方案,可以在不同的 Ruby 进程中将对象以普通文本传递,此外也适合 ruby 与那些支持 YAML 的语言之间交换数据用。

YAML 中数据主要由序列 (sequence) , map (有的也叫做 hash )和标量( scalar )来表示。语法比较简单,易于人们阅读。

 注释由 # 开头

 序列由 "-" 开头

 map 用 key:value 的格式

 "---" 表示一个 yaml 文档的开始

 list 和 hash 可以嵌套

 block 的概念:一个 block 是一段文本。

 Inline Collections :数据都写在一行  

集合类型   序列

 基本序列

可以在每一个新行前加“ - ”构成一个序列。

YAML 中,

- Henry

- Mike

- Tom 

在 Ruby 中,

[‘Henry’, ‘Mike’, ‘Tom’] 

 嵌套序列

使用位于空行上的“ - ”,你可以在一个序列内包含另一个序列。

-

- Henry

- Mike

- Tom 

在 Ruby 中,

[[‘Henry’, ‘Mike’, ‘Tom’]] 

使用缩进表示不同的层次,序列也可以表示更深层次的嵌套

-

-

- Henry

- Mike

- Tom

在 Ruby 中,

[[[‘Henry’, ‘Mike’, ‘Tom’]]] 

l  混合嵌套序列

在序列中也可以嵌套其他的 YAML 数据结构:

- Henry

-

  - 13

  - male

- Mike

- Henry

在 Ruby 中,

[‘Henry’, [‘13’ , ‘male’], ‘Mike’, ‘Henry’] 

  表

你可以使用 Key:value 的形式组织数据,每个 key:value 位于单独的一行,这样的数据结构称为表,也叫做哈希表或字典。

l  基本表

Grant:student

Tom:teacher 

在 Ruby 中,

{‘Grant’ => ‘student’, ‘Tom’ => ‘teacher’ } 

含有序列的表

Grant:student

Tom:

-    teacher

-    male  

在 Ruby 中,

{‘Grant’ => ‘student’, ‘Tom’ => [‘teacher’, ‘male’ } 

嵌套表

teacher: Mike

students:

Grant:13

Henry:14 

在 Ruby 中,

{   ‘teacher’ => ‘Mike’,

‘students’ => {

   ‘Grant’ => ‘13’ ,

   ‘Henry’ => ‘14’

}

混合表

grade: 1

teachers:

Mike:math

Jane:english

classes :

  -

Grant:13

Henry:14

-

  Jack:13

  Rose:13

     

在 Ruby 中,

{   ‘grade’ => ‘1’ ,

‘teachers’ =>

{

   ‘Mike’ => ‘math’,

   ‘Jane’ => ‘English’

}

  ‘classes’ => [

{

   ‘Grant’ => ‘13’ ,

   ‘Henry’ => ‘14’

},

{

   ‘Jack’ => ‘13’ ,

   ‘Rose’ => ‘13’

}

]

序列中嵌套表的缩写

当在序列中添加一个表时,可以

- worked on test.py:

  - This is a test 

在 Ruby 中,

[ {‘worked on test.py’ => [‘This is a test’] } ] 

表中嵌套序列的缩写

当在表中嵌套一个序列时,可以不需要缩进。

Students:

- ‘Grant’

- ‘Henry’ 

在 Ruby 中,

{‘Students’ => [‘Grant’, ‘Henry’] } 

 插入键 (Merge key)

可以使用插入键在一个表中插入另一个表

{ information:

       Name: Jane

       course: English

<<:

        Age: 25

在 Ruby 中 ,

{‘information’ => {

‘name’ => ‘Jane’,

‘course’ => ‘English’,

‘age’  => ‘25’

}

单行集合类型

单行序列

单行映射  

基本类型

String

Scalar

 NULL

 Boolean

 Integer

 Float

 Time

 Date

块   别名和锚 Aliases and Anchors )   文档

 

  Ruby 中 YAML 的使用

Ruby 中的 YAML 支持

Ruby1.8 已经包含了 YAML 支持了。只需要 require 进来就行了。

require 'yaml' 

class Person

        attr_accessor :name, :sex, :age 

        def initialize(name, gender, age)

           @name = name

           @gender = gender

           @age = age

        end

end 

# 创建一个对象

person=Person.new("Tom", "male", 15)

# 打印序列化之后的结果

puts person.to_yaml 

结果为:

--- !ruby/object:Person

age: 15

gender: male

name: Tom 

假设现在有一个 person.xml 文件内容为:

--- !ruby/object:Person

age: 25

gender: male

name: Henry 

如下代码:

# 从 person.yml 创建对象

person2 = YAML::load( File.open('d:\\person.yml') )

puts person2.inspect

puts person2.class # 结果是 Person

puts person2.name

执行结果为:

#<Person:0x2ebbf70 @name="Henry", @age=25, @gender="male">

Person

Henry
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YAMLYAML Ain't Markup Language)是一种人类可读的数据序列化格式,它被广泛用于配置文件、数据交换和文档等场景中。序列化是将复杂的数据结构转换为 YAML 格式的过程,而反序列化则是从 YAML 格式恢复数据到原始数据结构的过程。 **序列化教程:** 1. **安装库**:许多编程语言都有支持 YAML 序列化的库,比如 Python 的 PyYAML,JavaScript 的 `js-yaml` 等。确保你已经安装了对应的库。 2. **Python 示例**: ```python import yaml data = { 'name': 'John', 'age': 30, 'city': 'New York' } # 序列化 serialized_data = yaml.dump(data) print(serialized_data) # 输出:name: John age: 30 city: New York # 反序列化 deserialized_data = yaml.safe_load(serialized_data) print(deserialized_data) # 输出:{'name': 'John', 'age': 30, 'city': 'New York'} ``` 3. **保存和读取文件**:你可以选择将序列化后的数据保存到文件,然后在需要时读取并反序列化。 **反序列化教程:** 1. **处理结构复杂的对象**:YAML 通常能很好地处理嵌套的数据结构,如列表和字典。 2. **错误处理**:如果 YAML 文件格式错误或解析失败,需要捕获异常进行错误处理。 3. **跨语言支持**:如果你的应用涉及多个编程语言,了解不同语言如何处理 YAML序列化也是必要的。 **相关问题--:** 1. YAML 序列化和 JSON 序列化有什么区别? 2. 在 JavaScript 中如何进行 YAML序列化和反序列化? 3. 如何处理 YAML 文件中的注释和特殊字符?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值