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 Filter 钩子,这些模块包含在从 5.6.1 版开始的标准 Perl 源代码发行版中。除了随 Perl 发行的 *DB*_File 模块之外,CPAN 上提供的 BerkeleyDB 模块也支持 DBM Filter 钩子。有关 DBM Filter 钩子的更多详细信息,请参阅 perldbmfilter。
DBM Filter 允许在将键和/或值写入 DBM 文件之前以及在从 DBM 文件读回键和/或值之后,由用户定义的代码对其进行修改。例如,以下代码片段
$some_hash{"abc"} = 42;
可能会触发两个过滤器,一个用于写入键“abc”,另一个用于写入值 42。类似地,以下代码片段
my ($key, $value) = each %some_hash
将触发两个过滤器,一个用于读取键,另一个用于读取值。
与现有的 DBM Filter 功能类似,此模块安排使用键或值填充 $_
变量,过滤器将检查该键或值。这通常意味着大多数 DBM 过滤器往往非常短。
与标准 DBM Filter 钩子相比,主要增强功能包括
更简洁的界面。
能够轻松地将多个过滤器应用到单个 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
需要发送到过滤器的任何可选参数。请参阅 encode 过滤器,了解使用参数的模块示例。
实现罐装过滤器的模块可以采用两种形式之一。下面是第一个的模板
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 包含在字符串中。此过滤器将确保 C 应用程序可以读取写入 DBM 文件的所有数据。
在编写 DBM 过滤器时,确保在 DBM 过滤器就位时可以检索您已写入的所有数据非常重要。实际上,这意味着对 Store 方法中的数据应用任何转换,都应在 Fetch 方法中应用完全相反的操作。
如果您没有提供完全相反的转换,您会发现这样的代码不会按您预期的那样执行。
while (my ($k, $v) = each %hash)
{
...
}
根据转换,您会发现以下一个或多个情况会发生
循环永远不会终止。
检索的记录太少。
检索的记录太多。
循环会暂时做正确的事情,但它会意外失败。
这只是对前一节的重述。除非你完全确定自己知道自己在做什么,否则避免混合过滤和非过滤数据。
假设你需要与一个旧版 C 应用程序进行交互,该应用程序将键存储为 C int,并将值和空终止 UTF-8 字符串存储。以下是设置方法
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 <[email protected]>