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 データベースから値を 読み込む毎に起動されます。
これらのメソッドは 0 個から 4 個全てまで好きな組み合わせで使えます。
全てのフィルタメソッドはもしあれば既に登録されているフィルタを、 なければ undef
を返します。
フィルタを削除するには undef
を渡します。
それぞれのフィルタが Perl によって呼び出されると、$_
のローカルコピーには フィルタされるキーや値が入ります。 フィルタリングは $_
の内容を変更することによって行われます。 フィルタからの返り値は無視されます。
全てのキー、全ての値、あるいはその両方に対して同じ変換を 常に 行いたいような問題の種類には DBM フィルタが便利です。
例えば、以下のようなシナリオを考えます。 サードパーティ C アプリケーションと共有する必要がある DBM データベースが あります。 C アプリケーションは 全ての キーと値が NULL 終端されていることを 仮定しています。 残念ながら Perl が DBM データベースに書き込むときには NULL 終端しないので、 Perl アプリケーションは自分自身で NULL 終端を管理する必要があります。 データベースに書き込むときに、以下のようなことをする必要があります:
$hash{"$key\0"} = "$value\0";
同様に、すでにあるキーや値の長さを考慮するときには NULL を計算に入れる 必要があります。
メインアプリケーションのコードでは NULL 終端問題を無視して、 データベースに書き込むときには自動的に終端の NULL を追加して、 データベースから読み込むときには自動的に削除する機構があれば とても便利です。 既に想像はしていると思いますが、これは DBM フィルタが簡単に修正できる 問題です。
use strict;
use warnings;
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 モジュールでも 動作します。
出来れば、それぞれのフィルタの内容は自己説明的であるべきです。 両方の "fetch" フィルタは終端の NULL を削除し、両方の "store" フィルタは 終端する NULL を追加します。
もう一つの実際の生活の例です。 デフォルトでは、Perl が DBM データベースに書き込むときはいつでも、 キーと値を文字列として書き込みます。 従って、以下のように使うと:
$hash{12345} = "something";
キー 12345 は、5 バイトの文字列 "12345" として DBM データベースとして 保管されます。 実際に DBM データベースに C の int としてキーを保管したい場合は、 書き込むときに pack
を使い、読み込むときに unpack
を使う 必要があります。
以下はこのために DBM を使います:
use strict;
use warnings;
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