內容

名稱

DBM_Filter -- 過濾 DBM 鍵/值

語法

use DBM_Filter ;
use SDBM_File; # or DB_File, GDBM_File, NDBM_File, or ODBM_File

$db = tie %hash, ...

$db->Filter_Push(Fetch => sub {...},
                 Store => sub {...});

$db->Filter_Push('my_filter1');
$db->Filter_Push('my_filter2', params...);

$db->Filter_Key_Push(...) ;
$db->Filter_Value_Push(...) ;

$db->Filter_Pop();
$db->Filtered();

package DBM_Filter::my_filter1;

sub Store { ... }
sub Fetch { ... }

1;

package DBM_Filter::my_filter2;

sub Filter
{
    my @opts = @_;
    ...
    return (
        sub Store { ... },
        sub Fetch { ... } );
}

1;

說明

此模組提供一個介面,允許將篩選器套用至與 DBM 檔案關聯的繫結雜湊。它建立在所有 *DB*_File 模組中存在的 DBM 篩選器掛勾之上,這些模組包含在從 5.6.1 版開始的標準 Perl 原始碼發行版中。除了與 Perl 一起發行的 *DB*_File 模組外,CPAN 上提供的 BerkeleyDB 模組也支援 DBM 篩選器掛勾。請參閱 perldbmfilter 以取得有關 DBM 篩選器掛勾的更多詳細資訊。

什麼是 DBM 篩選器?

DBM 篩選器允許在寫入 DBM 檔案之前和從 DBM 檔案讀回之後,透過一些使用者定義的程式碼來修改繫結雜湊中的鍵和/或值。例如,這段程式碼片段

$some_hash{"abc"} = 42;

可能會觸發兩個篩選器,一個用於寫入鍵「abc」,另一個用於寫入值 42。類似地,這段程式片段

my ($key, $value) = each %some_hash

將觸發兩個篩選器,一個用於讀取鍵,另一個用於讀取值。

與現有的 DBM 篩選器功能一樣,此模組會安排將鍵或值填入 $_ 變數,以便篩選器進行檢查。這通常表示大多數 DBM 篩選器往往非常簡短。

有什麼新功能?

與標準 DBM 篩選器掛鉤相比,主要的增強功能有

方法

此模組會安排透過 tie 呼叫傳回的物件提供下列方法。

$db->Filter_Push() / $db->Filter_Key_Push() / $db->Filter_Value_Push()

將篩選器新增至資料庫 $db 的篩選器堆疊。三種格式的差異僅在於它們是否套用至 DBM 鍵、DBM 值或兩者。

Filter_Push

篩選器套用至鍵和值兩者

Filter_Key_Push

篩選器套用至鍵。

Filter_Value_Push

篩選器套用至值。

$db->Filter_Pop()

移除套用至與 $db 關聯的 DBM 檔案的最後一個篩選器(如果存在)。

$db->Filtered()

如果套用任何篩選器至與 $db 關聯的 DBM,則傳回 TRUE。否則傳回 FALSE。

撰寫篩選器

篩選器可以透過兩種主要方式建立

立即篩選器

立即篩選器允許您在將篩選器套用至 dbm 的點指定要使用的篩選器程式碼。在此模式中,Filter_*_Push 方法預期會收到兩個參數。

my $db = tie %hash, 'SDBM_File', ...
$db->Filter_Push( Store => sub { },
                  Fetch => sub { });

Store 關聯的程式碼參考會在任何鍵/值寫入資料庫之前呼叫,而與 Fetch 關聯的程式碼參考會在任何鍵/值從資料庫讀取之後呼叫。

例如,這裡有一個範例篩選器,它會在寫入 DBM 檔案之前,在所有字串中加入一個尾隨的 NULL 字元,並在從 DBM 檔案中讀取時移除尾隨的 NULL

my $db = tie %hash, 'SDBM_File', ...
$db->Filter_Push( Store => sub { $_ .= "\x00" ; },
                  Fetch => sub { s/\x00$// ;    });

注意事項

  1. Store 和 Fetch 篩選器都會操作 $_

罐頭篩選器

立即篩選器適用於一次性的情況。對於更通用的問題,將篩選器封裝在自己的模組中會很有用。

罐頭篩選器的用法是

$db->Filter_Push("name", params)

其中

"name"

是要載入的模組名稱。如果指定的字串不包含套件分隔字元 "::",則假設它指的是完整的模組名稱 "DBM_Filter::name"。這表示這個模組中包含的罐頭篩選器的完整名稱 "null" 和 "utf8" 為

DBM_Filter::null
DBM_Filter::utf8
params

任何需要傳送至篩選器的選用參數。請參閱編碼篩選器,以取得使用參數的模組範例。

實作罐頭篩選器的模組可以採用兩種形式之一。以下是第一種形式的範本

package DBM_Filter::null ;

use strict;
use warnings;

sub Store 
{
    # store code here    
}

sub Fetch
{
    # fetch code here
}

1;

注意事項

  1. 套件名稱使用 DBM_Filter:: 前綴。

  2. 模組必須同時具有 Store 和 Fetch 方法。如果只存在其中一個,或兩個都不存在,則會擲出致命錯誤。

第二種形式允許篩選器使用封閉函式保留狀態資訊,因此

package DBM_Filter::encoding ;

use strict;
use warnings;

sub Filter
{
    my @params = @_ ;

    ...
    return {
        Store   => sub { $_ = $encoding->encode($_) },
        Fetch   => sub { $_ = $encoding->decode($_) }
        } ;
}

1;

在此範例中,「Store」和「Fetch」方法封裝在「Filter」方法內。

包含的篩選器

這個模組提供許多罐頭篩選器。它們涵蓋了與 DBM 檔案介接時需要篩選器的大部分主要領域。它們也作為您自己的篩選器的範本。

包含的篩選器為

備註

維持往返完整性

在撰寫 DBM 篩選器時,確保在 DBM 篩選器就位時可以擷取已寫入的所有資料非常重要。實際上,這表示在儲存方法中對資料套用的任何轉換,都應該在擷取方法中套用完全相反的運算。

如果您沒有提供完全相反的轉換,您會發現像這樣的程式碼不會如您預期般運作。

while (my ($k, $v) = each %hash)
{
    ...
}

根據轉換,您會發現以下一項或多項情況會發生

  1. 迴圈永遠不會終止。

  2. 擷取的記錄太少。

  3. 擷取的記錄太多。

  4. 迴圈會在一段時間內做正確的事,但會意外失敗。

請勿在同一個資料庫檔案中混合已篩選和未篩選的資料。

這只是上一節的重新表述。除非您完全確定知道自己在做什麼,否則請避免混合已篩選和未篩選的資料。

範例

假設您需要與將鍵儲存為 C int,而值和 null 結束的 UTF-8 字串的舊式 C 應用程式進行交互操作。以下是設定方式

my $db = tie %hash, 'SDBM_File', ...

$db->Filter_Key_Push('int32') ;

$db->Filter_Value_Push('utf8');
$db->Filter_Value_Push('null');

另請參閱

<DB_File>、GDBM_FileNDBM_FileODBM_FileSDBM_Fileperldbmfilter

作者

Paul Marquess <pmqs@cpan.org>