Perl提供了一个Storable模块,用来对数据结构进行序列化(serialization,Perl中称为冻结),也就是将数据结构保存为二进制数据。html
Storabel的freeze和thaw函数分别用来冻结(序列化)和解冻(反序列化):网络
#!/usr/bin/perl use 5.010; use Storable qw(freeze thaw); %hash=( 'longshuai'=>{ 'gender'=>'male', 'age' =>18, 'prov' =>'jiangxi', }, 'wugui'=>{ 'gender'=>'male', 'age' =>20, 'prov' =>'zhejiang', }, 'xiaofang'=>{ 'gender'=>'female', 'age' =>19, 'prov' =>'fujian', }, ); @name=('fairy',[qw(longshuai wugui xiaofang)]); $frozen = freeze [\%hash,\@name]; # 冻结引用,返回一个冻结后的列表 #say $frozen; # 输出一堆乱码 $thaw_out=thaw($frozen); # 解冻,返回引用列表 say $thaw_out->[0]; # 输出:HASH(0x557171a4cff8) say $thaw_out->[0]{wugui}{prov}; # 输出:zhejiang say $thaw_out->[1]; # 输出:ARRAY(0x557171a4d220) say $thaw_out->[1][1][2]; # 输出:xiaofang
上面的示例中,使用freeze冻结两个数据结构后,冻结后的二进制数据内容将赋值给一个标量变量,注意它返回的是相似于字符串那种形式的,只不过这段字符串是二进制格式的。数据结构
使用thaw解冻后,将返回一个匿名列表,列表中的元素是各冻结的数据结构的引用。对于上面的示例来讲,返回值相似如此结构[$ref_hash,$ref_name]
,将其赋值给一个引用变量$thaw_out
,而后就能够经过$thaw_out->[0]
和$thaw_out->[1]
分别访问这两个引用。函数
以下图描述:ui
freeze序列化过程:code
thaw反序列化过程:htm
Storable模块能够将数据结构序列化后持久化保存到文件中,或经过TCP套接字传输出去。对象
store和nstore用于将序列化数据进行持久化,它们用法同样,以下:blog
store \%ref_hash, 'file'; store [\%ref_hash,\@ref_arr], 'file'; nstore \%ref_hash, 'file'; nstore [\%ref_hash,\@ref_arr], 'file';
可是store存储序列化数据时默认采用的是主机字节序(host byte order),nstore默认采用的是网络字节序(network byte order),采用网络字节序能够保证被TCP套接字传输出去时,远程主机能以彻底一致的字节序方式读取数据。因此,要想经过网络传输序列化的对象时,须要使用nstore。dns
小知识:主机字节序和网络字节序
多字节数据对象在存储时,必须考虑两个问题:
- 这段数据对象要存储到哪一个地址
- 存储时如何排列这些字节
这里不考虑存储的地址问题。对于待存储的数值"0x1122"来讲,11属于高位字节,22属于低位字节。对于存储时考虑以何种字节排列方式来讲,有两种方式:大端字节序和小端字节序。假设要存储的数据对象"0x1234567":
- 大端字节序(big-endian):存储时,高位在前,低位在后,因此存储的时候,和上面源数据格式同样"01 23 45 67"
- 小端字节序(little-endian):存储时,高位在后,低位在前,因此存储的时候,和上面源数据格式相反"67 45 23 01"
大端字节序对人类来讲比较容易理解,但几乎全部计算机都是采用小端字节序存储的,因此也称为主机字节序。而TCP/IP协议规定,网络传输时的网络字节序都采用大端字节序传输,这样一来全部网络传输的数据都规范化,远程主机总会按照大端字节序去读取传输过来的数据。
store和nstore持久化的序列化数据能够经过retrieve函数读取并反序列化。retrieve返回的值和thaw的返回结果是同样的。
my $ref_list = retrieve 'file';
如下是nstore和retrieve的一个示例:
#!/usr/bin/perl use 5.010; use Storable qw(nstore retrieve); %hash=( 'longshuai'=>{ 'gender'=>'male', 'age' =>18, 'prov' =>'jiangxi', }, 'wugui'=>{ 'gender'=>'male', 'age' =>20, 'prov' =>'zhejiang', }, 'xiaofang'=>{ 'gender'=>'female', 'age' =>19, 'prov' =>'fujian', }, ); @name=('fairy',[qw(longshuai wugui xiaofang)]); nstore [\%hash,\@name],'/tmp/tmp_data'; # 将数据序列化并持久化到文件 $ref_list=retrieve '/tmp/tmp_data'; # 反序列化并读取数据 say $ref_list->[0]; # 输出:HASH(0x55aee8340318) say $ref_list->[0]{wugui}{prov}; # 输出:zhejiang say $ref_list->[1]; # 输出:ARRAY(0x55aee8340480) say $ref_list->[1][1][2]; # 输出:xiaofang
下面示例涉及到文件句柄的标量引用,如不理解,请跳过。
例如,将数据结构冻结到一个字符串$string
中存储起来:
use Storable; open my $string_fh,">",\my $string or die "...$!"; nstore_fd \@data,$string_fh; close $string_fh;
从持久化数据的变量$string
中解冻:
open my $string_fh1,"<",\$string or die "$!"; $new_hash = fd_retrieve($string_fh1); close $string_fh1;
如此,数据结构就存储到$new_hash
这个引用中。
例如,将前文的数据结构%hash
存储起来,并当即解冻:
#!/usr/bin/perl use Storable qw(store_fd nstore_fd fd_retrieve); use Data::Dumper; open my $string_fh,">",\my $string; nstore_fd [\%hash],$string_fh; close $string_fh; print Dumper($string); # 输出:一大堆乱码二进制 open my $string_fh1,"<",\$string or die "$!"; $new_hash = fd_retrieve($string_fh1); close $string_fh1; print Dumper($new_hash); # 输出:hash数据结构
关于浅拷贝、深拷贝,见Perl的浅拷贝和深度拷贝