內容

名稱

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 篩選器。它們之間唯一的差異在於安裝篩選器的位置。

總結如下

filter_store_key

如果已使用此方法安裝篩選器,則每次將金鑰寫入 DBM 資料庫時,都會呼叫該篩選器。

filter_store_value

如果已使用此方法安裝篩選器,則每次將值寫入 DBM 資料庫時,都會呼叫該篩選器。

filter_fetch_key

如果使用此方法安裝了篩選器,則每次從 DBM 資料庫中讀取金鑰時,都會呼叫該篩選器。

filter_fetch_value

如果使用此方法安裝了篩選器,則每次從 DBM 資料庫中讀取值時,都會呼叫該篩選器。

你可以使用從無到全部四種方法的任意組合。

如果存在,所有篩選器方法都會傳回現有的篩選器,否則會傳回 undef

若要刪除篩選器,請將 undef 傳遞給它。

篩選器

Perl 呼叫每個篩選器時,$_ 的本機副本將包含要篩選的金鑰或值。透過修改 $_ 的內容來達成篩選。將忽略篩選器的回傳碼。

範例:NULL 終止問題。

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。

另一個範例:金鑰是 C int。

以下是另一個實際範例。預設情況下,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_FileGDBM_FileNDBM_FileODBM_FileSDBM_File

作者

Paul Marquess