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 { ... } );
上述四个 filter_*
方法在所有随 Perl 附带的 DBM 模块中均可用,即 DB_File、GDBM_File、NDBM_File、ODBM_File 和 SDBM_File。
每个方法的工作方式相同,用于安装(或卸载)单个 DBM 过滤器。它们之间的唯一区别是安装过滤器的放置位置。
总结如下
如果已使用此方法安装了过滤器,则每次将键写入 DBM 数据库时都会调用该过滤器。
如果已使用此方法安装了过滤器,则每次将值写入 DBM 数据库时,都会调用该过滤器。
如果已使用此方法安装了过滤器,则每次从 DBM 数据库读取键时,都会调用该过滤器。
如果已使用此方法安装了过滤器,则每次从 DBM 数据库读取值时,都会调用该过滤器。
你可以使用从无到全部四种方法的任意组合。
如果存在,所有过滤器方法都会返回现有过滤器,否则返回 undef
。
要删除过滤器,请向其传递 undef
。
当 Perl 调用每个过滤器时,$_
的本地副本将包含要过滤的键或值。通过修改 $_
的内容来实现过滤。将忽略过滤器返回的代码。
DBM 过滤器对于你始终希望对所有键、所有值或两者进行相同转换的问题类别很有用。
例如,考虑以下场景。你有一个需要与第三方 C 应用程序共享的 DBM 数据库。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