1. 程式人生 > >Perl資料序列化和持久化(入門):Storable模組

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

深拷貝:dclone