Perl資料序列化和持久化(入門):Storable模組
Perl提供了一個Storable模組,用來對資料結構進行序列化(serialization,Perl中稱為凍結),也就是將資料結構儲存為二進位制資料。
- 序列化後的資料可以寫入檔案實現持久化,可以將持久化檔案拷貝給遠端機器
- 也可以通過網路套接字將序列化資料傳遞給遠端機器
- 序列化後的資料在任意機器上都可以反序列化(deserialization,Perl中稱為解凍)得到原始的資料結構
- 序列化資料結構時是進行深拷貝的,序列化完成後,修改原始資料,不會影響反序列化的結果
序列化:freeze、nfreeze和thaw
Storabel的freeze和thaw函式分別用來凍結(序列化)和解凍(反序列化):
- freeze凍結的是資料物件,不包括它們的引用和名稱
- freeze的引數需要是引用,可以是多個引用引數,返回的是二進位制的凍結序列,各資料結構序列化在不同行
- thaw的引數是引用變數,返回的是一個匿名列表,列表各元素對應freeze凍結時的各資料結構
- nfreeze也是凍結,但是按照網路位元組序進行序列化,適合遠端傳輸序列化時的標量名稱,見下一小節對主機位元組序和網路位元組序的描述
#!/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]
分別訪問這兩個引用。
如下圖描述:
freeze序列化過程:
thaw反序列化過程:
持久化:store、nstore和retrieve
Storable模組可以將資料結構序列化後持久化儲存到檔案中,或通過TCP套接字傳輸出去。
store和nstore用於將序列化資料進行持久化,它們用法一樣,如下:
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。
小知識:主機位元組序和網路位元組序
多位元組資料物件在儲存時,必須考慮兩個問題:
- 這段資料物件要儲存到哪個地址
- 儲存時如何排列這些位元組
這裡不考慮儲存的地址問題。對於待儲存的數值"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