perldbmfilter - Perl DBM 篩選器
$db = tie %hash, 'DBM', ...
$old_filter = $db->filter_store_key ( sub { ... } );
$old_filter = $db->filter_store_value( sub { ... } );
$old_filter = $db->filter_fetch_key ( sub { ... } );
$old_filter = $db->filter_fetch_value( sub { ... } );
Perl 附帶的所有 DBM 模組中,都提供上述四個 filter_*
方法,分別為 DB_File、GDBM_File、NDBM_File、ODBM_File 和 SDBM_File。
每個方法的運作方式相同,用於安裝(或解除安裝)單一 DBM 篩選器。它們之間唯一的差異在於安裝篩選器的位置。
總結如下
如果已使用此方法安裝篩選器,則每次將金鑰寫入 DBM 資料庫時,都會呼叫該篩選器。
如果已使用此方法安裝篩選器,則每次將值寫入 DBM 資料庫時,都會呼叫該篩選器。
如果使用此方法安裝了篩選器,則每次從 DBM 資料庫中讀取金鑰時,都會呼叫該篩選器。
如果使用此方法安裝了篩選器,則每次從 DBM 資料庫中讀取值時,都會呼叫該篩選器。
你可以使用從無到全部四種方法的任意組合。
如果存在,所有篩選器方法都會傳回現有的篩選器,否則會傳回 undef
。
若要刪除篩選器,請將 undef
傳遞給它。
Perl 呼叫每個篩選器時,$_
的本機副本將包含要篩選的金鑰或值。透過修改 $_
的內容來達成篩選。將忽略篩選器的回傳碼。
DBM 篩選器適用於一類問題,在這些問題中,你總是想要對所有金鑰、所有值或兩者進行相同的轉換。
例如,考慮以下情況。你有一個 DBM 資料庫,需要與第三方 C 應用程式共用。C 應用程式假設所有金鑰和值都是以 NULL 終止。很不幸的是,當 Perl 寫入 DBM 資料庫時,它不會使用 NULL 終止,因此你的 Perl 應用程式必須自行管理 NULL 終止。當你寫入資料庫時,你必須使用類似以下的內容
$hash{"$key\0"} = "$value\0";
類似地,在考慮現有金鑰/值的長度時,需要考慮 NULL。
如果你可以在主應用程式碼中忽略 NULL 終止問題,並有一個機制可以在每次寫入資料庫時自動將終止 NULL 新增到所有金鑰和值,並在從資料庫讀取時將它們移除,那就好多了。我敢肯定你已經猜到了,這是 DBM 篩選器可以輕鬆修復的問題。
use v5.36;
use SDBM_File;
use Fcntl;
my %hash;
my $filename = "filt";
unlink $filename;
my $db = tie(%hash, 'SDBM_File', $filename, O_RDWR|O_CREAT, 0640)
or die "Cannot open $filename: $!\n";
# Install DBM Filters
$db->filter_fetch_key ( sub { s/\0$// } );
$db->filter_store_key ( sub { $_ .= "\0" } );
$db->filter_fetch_value(
sub { no warnings 'uninitialized'; s/\0$// } );
$db->filter_store_value( sub { $_ .= "\0" } );
$hash{"abc"} = "def";
my $a = $hash{"ABC"};
# ...
undef $db;
untie %hash;
上述程式碼使用 SDBM_File,但它會與任何 DBM 模組一起使用。
希望每個篩選器的內容都是不言自明的。兩個「擷取」篩選器都會移除終止 NULL,而兩個「儲存」篩選器都會新增終止 NULL。
以下是另一個實際範例。預設情況下,Perl 每次寫入 DBM 資料庫時,它總是將金鑰和值寫入為字串。因此,當你使用這個時
$hash{12345} = "something";
金鑰 12345 將以 5 位元組字串「12345」儲存在 DBM 資料庫中。如果你實際上希望將金鑰以 C int 儲存在 DBM 資料庫中,則必須在寫入時使用 pack
,在讀取時使用 unpack
。
以下是這樣做的 DBM 篩選器
use v5.36;
use DB_File;
my %hash;
my $filename = "filt";
unlink $filename;
my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666,
$DB_HASH or die "Cannot open $filename: $!\n";
$db->filter_fetch_key ( sub { $_ = unpack("i", $_) } );
$db->filter_store_key ( sub { $_ = pack ("i", $_) } );
$hash{123} = "def";
# ...
undef $db;
untie %hash;
上述程式碼使用 DB_File,但它會與任何 DBM 模組一起使用。
這次只使用了兩個篩選器;我們只需要處理金鑰的內容,因此不需要安裝任何值篩選器。
DB_File、GDBM_File、NDBM_File、ODBM_File 和 SDBM_File。
Paul Marquess