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 檔案讀回之後,透過一些使用者定義的程式碼來修改繫結雜湊中的鍵和/或值。例如,這段程式碼片段
$some_hash{"abc"} = 42;
可能會觸發兩個篩選器,一個用於寫入鍵「abc」,另一個用於寫入值 42。類似地,這段程式片段
my ($key, $value) = each %some_hash
將觸發兩個篩選器,一個用於讀取鍵,另一個用於讀取值。
與現有的 DBM 篩選器功能一樣,此模組會安排將鍵或值填入 $_
變數,以便篩選器進行檢查。這通常表示大多數 DBM 篩選器往往非常簡短。
與標準 DBM 篩選器掛鉤相比,主要的增強功能有
更簡潔的介面。
能夠輕鬆地將多個篩選器套用至單一 DBM 檔案。
能夠建立「罐頭」篩選器。這些篩選器允許將常用的篩選器封裝成獨立的模組。
此模組會安排透過 tie
呼叫傳回的物件提供下列方法。
將篩選器新增至資料庫 $db
的篩選器堆疊。三種格式的差異僅在於它們是否套用至 DBM 鍵、DBM 值或兩者。
移除套用至與 $db
關聯的 DBM 檔案的最後一個篩選器(如果存在)。
如果套用任何篩選器至與 $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$// ; });
注意事項
Store 和 Fetch 篩選器都會操作 $_
。
立即篩選器適用於一次性的情況。對於更通用的問題,將篩選器封裝在自己的模組中會很有用。
罐頭篩選器的用法是
$db->Filter_Push("name", params)
其中
是要載入的模組名稱。如果指定的字串不包含套件分隔字元 "::",則假設它指的是完整的模組名稱 "DBM_Filter::name"。這表示這個模組中包含的罐頭篩選器的完整名稱 "null" 和 "utf8" 為
DBM_Filter::null
DBM_Filter::utf8
任何需要傳送至篩選器的選用參數。請參閱編碼篩選器,以取得使用參數的模組範例。
實作罐頭篩選器的模組可以採用兩種形式之一。以下是第一種形式的範本
package DBM_Filter::null ;
use strict;
use warnings;
sub Store
{
# store code here
}
sub Fetch
{
# fetch code here
}
1;
注意事項
套件名稱使用 DBM_Filter::
前綴。
模組必須同時具有 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 檔案介接時需要篩選器的大部分主要領域。它們也作為您自己的篩選器的範本。
包含的篩選器為
utf8
這個模組會確保寫入 DBM 的所有資料都編碼為 UTF-8。
這個模組需要 Encode 模組。
encode
允許您選擇字元編碼將儲存在 DBM 檔案中。
compress
此篩選器會在資料寫入資料庫之前將所有資料壓縮,並在讀取時解壓縮。
此模組需要 Compress::Zlib。
int32
此模組用於與使用 C int 作為 DBM 檔案中鍵和/或值的 C/C++ 應用程式進行交互操作時。
null
此模組確保寫入 DBM 檔案的所有資料都以 null 結束。當您有需要與 C 程式也使用的 DBM 檔案進行交互操作的 perl 程式時,這很有用。一個相當常見的問題是,C 應用程式在寫入 DBM 檔案時會在字串中包含終止 null。此篩選器將確保寫入 DBM 檔案的所有資料都能被 C 應用程式讀取。
在撰寫 DBM 篩選器時,確保在 DBM 篩選器就位時可以擷取已寫入的所有資料非常重要。實際上,這表示在儲存方法中對資料套用的任何轉換,都應該在擷取方法中套用完全相反的運算。
如果您沒有提供完全相反的轉換,您會發現像這樣的程式碼不會如您預期般運作。
while (my ($k, $v) = each %hash)
{
...
}
根據轉換,您會發現以下一項或多項情況會發生
迴圈永遠不會終止。
擷取的記錄太少。
擷取的記錄太多。
迴圈會在一段時間內做正確的事,但會意外失敗。
這只是上一節的重新表述。除非您完全確定知道自己在做什麼,否則請避免混合已篩選和未篩選的資料。
假設您需要與將鍵儲存為 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_File、NDBM_File、ODBM_File、SDBM_File、perldbmfilter
Paul Marquess <pmqs@cpan.org>