DB_File
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- СИНТАКСИС
- ОПИСАНИЕ
- DB_HASH
- DB_BTREE
- DB_RECNO
- ИНТЕРФЕЙС API
- ФИЛЬТРЫ DBM
- УКАЗАНИЯ И СОВЕТЫ
- ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
- СПИСОК ЛИТЕРАТУРЫ
- ИСТОРИЯ
- ОШИБКИ
- ТЕХНИЧЕСКАЯ ПОДДЕРЖКА
- ДОСТУПНОСТЬ
- АВТОРСКИЕ ПРАВА
- СМОТРИТЕ ТАКЖЕ
- АВТОР
НАЗВАНИЕ
DB_File — доступ к Berkeley DB версии 1.x в Perl 5
СИНТАКСИС
use DB_File;
[$X =] tie %hash, 'DB_File', [$filename, $flags, $mode, $DB_HASH] ;
[$X =] tie %hash, 'DB_File', $filename, $flags, $mode, $DB_BTREE ;
[$X =] tie @array, 'DB_File', $filename, $flags, $mode, $DB_RECNO ;
$status = $X->del($key [, $flags]) ;
$status = $X->put($key, $value [, $flags]) ;
$status = $X->get($key, $value [, $flags]) ;
$status = $X->seq($key, $value, $flags) ;
$status = $X->sync([$flags]) ;
$status = $X->fd ;
# BTREE only
$count = $X->get_dup($key) ;
@list = $X->get_dup($key) ;
%list = $X->get_dup($key, 1) ;
$status = $X->find_dup($key, $value) ;
$status = $X->del_dup($key, $value) ;
# RECNO only
$a = $X->length;
$a = $X->pop ;
$X->push(list);
$a = $X->shift;
$X->unshift(list);
@r = $X->splice(offset, length, elements);
# DBM Filters
$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 { ... } ) ;
untie %hash ;
untie @array ; ОПИСАНИЕ
DB_File — это модуль, который позволяет программам Perl использовать возможности Berkeley DB версии 1.x (если у вас более новая версия DB, см. «Использование DB_File с Berkeley DB версии 2 или выше»). Предполагается, что у вас есть справочная документация к Berkeley DB при чтении этого руководства. Данный интерфейс тесно привязан к интерфейсу Berkeley DB.
Berkeley DB — это библиотека C, которая предоставляет согласованный интерфейс к ряду форматов баз данных. DB_File предоставляет интерфейс ко всем трём типам баз данных, поддерживаемым в настоящее время Berkeley DB.
Типы файлов:
- DB_HASH
-
Этот тип базы данных позволяет хранить произвольные пары «ключ-значение» в файлах данных. Это эквивалентно функциональности, предоставляемой другими пакетами хеширования, такими как DBM, NDBM, ODBM, GDBM и SDBM. Однако файлы, созданные с помощью DB_HASH, несовместимы ни с одним из упомянутых пакетов.
В Berkeley DB реализован алгоритм хеширования по умолчанию, который будет адекватен для большинства приложений. Если вам нужно использовать свой собственный алгоритм хеширования, вы можете написать его на Perl и заставить DB_File использовать его вместо этого.
- DB_BTREE
-
Формат btree позволяет хранить произвольные пары «ключ-значение» в отсортированном сбалансированном двоичном дереве.
Как и с форматом DB_HASH, вы можете предоставить пользовательскую Perl-функцию для сравнения ключей. Однако по умолчанию ключи хранятся в лексикографическом порядке.
- DB_RECNO
-
DB_RECNO позволяет манипулировать как файлами с фиксированной длиной, так и файлами с переменной длиной, используя тот же интерфейс «ключ-значение», что и в DB_HASH и DB_BTREE. В этом случае ключ будет содержать номер записи (строки).
Использование DB_File с Berkeley DB версии 2 или выше
Хотя DB_File предназначен для использования с Berkeley DB версии 1, его также можно использовать с версиями 2, 3 или 4. В этом случае интерфейс ограничен функциональностью Berkeley DB 1.x. Там, где интерфейс версии 2 или выше отличается, DB_File организует его работу так, как будто это версия 1. Эта функция позволяет скриптам DB_File, созданным с версией 1, переходить на версии 2 или выше без изменений.
Если вы хотите использовать новые возможности, доступные в Berkeley DB 2.x или выше, используйте модуль Perl BerkeleyDB вместо этого.
Примечание: Формат файлов базы данных несколько раз менялся в Berkeley DB версий 2, 3 и 4. Если вы не можете восстановить свои базы данных, вам необходимо экспортировать существующие базы данных с помощью утилиты db_dump или db_dump185, которая входит в комплект поставки Berkeley DB. После перестройки DB_File для использования с Berkeley DB версии 2 или выше, ваши базы данных можно восстановить с помощью db_load. Обратитесь к документации Berkeley DB для получения дополнительной информации.
Перед использованием версии 2.x или выше Berkeley DB с DB_File, пожалуйста, прочтите «АВТОРСКИЕ ПРАВА».
Интерфейс с Berkeley DB
DB_File позволяет получить доступ к файлам Berkeley DB с помощью механизма tie() в Perl 5 (подробности см. в «tie()» в perlfunc). Эта возможность позволяет DB_File получать доступ к файлам Berkeley DB, используя либо ассоциативный массив (для типов файлов DB_HASH и DB_BTREE), либо обычный массив (для типа файла DB_RECNO).
Помимо интерфейса tie(), вы также можете напрямую получить доступ к большинству функций, предоставляемых API Berkeley DB. См. «ИНТЕРФЕЙС API».
Открытие файла базы данных Berkeley DB
Berkeley DB использует функцию dbopen() для открытия или создания базы данных. Вот прототип функции dbopen() на C:
DB*
dbopen (const char * file, int flags, int mode,
DBTYPE type, const void * openinfo) Параметр type — это перечисление, которое указывает, какой из трёх интерфейсных методов (DB_HASH, DB_BTREE или DB_RECNO) использовать. В зависимости от выбранного метода, конечный параметр openinfo указывает на структуру данных, которая позволяет настраивать конкретный интерфейсный метод.
В DB_File этот интерфейс обрабатывается немного по-другому. Вот эквивалентный вызов с использованием DB_File:
tie %array, 'DB_File', $filename, $flags, $mode, $DB_HASH ; Параметры filename, flags и mode являются прямым эквивалентом своих аналогов в dbopen(). Конечный параметр $DB_HASH выполняет функцию параметров type и openinfo в dbopen().
В примере выше $DB_HASH фактически является предварительно определённой ссылкой на объект хеша. В DB_File есть три такие предварительно определённые ссылки. Помимо $DB_HASH, есть также $DB_BTREE и $DB_RECNO.
Допустимые ключи в каждой из этих предварительно определённых ссылок ограничены именами, используемыми в соответствующей структуре C. Например, ссылка $DB_HASH будет допускать только ключи, называемые bsize, cachesize, ffactor, hash, lorder и nelem.
Чтобы изменить одно из этих элементов, просто присвойте ему новое значение:
$DB_HASH->{'cachesize'} = 10000 ; Три предварительно определённые переменные $DB_HASH, $DB_BTREE и $DB_RECNO обычно подходят для большинства приложений. Если вам нужно создать дополнительные экземпляры этих объектов, для каждого типа файла доступны конструкторы.
Ниже примеры конструкторов и допустимых опций для DB_HASH, DB_BTREE и DB_RECNO соответственно.
$a = new DB_File::HASHINFO ;
$a->{'bsize'} ;
$a->{'cachesize'} ;
$a->{'ffactor'};
$a->{'hash'} ;
$a->{'lorder'} ;
$a->{'nelem'} ;
$b = new DB_File::BTREEINFO ;
$b->{'flags'} ;
$b->{'cachesize'} ;
$b->{'maxkeypage'} ;
$b->{'minkeypage'} ;
$b->{'psize'} ;
$b->{'compare'} ;
$b->{'prefix'} ;
$b->{'lorder'} ;
$c = new DB_File::RECNOINFO ;
$c->{'bval'} ;
$c->{'cachesize'} ;
$c->{'psize'} ;
$c->{'flags'} ;
$c->{'lorder'} ;
$c->{'reclen'} ;
$c->{'bfname'} ; Значения, хранящиеся в хешах выше, в основном являются прямым эквивалентом своих аналогов в C. Как и их аналоги в C, все они имеют значения по умолчанию — это означает, что вам не нужно устанавливать все значения, если вы хотите изменить только одно. Вот пример:
$a = new DB_File::HASHINFO ;
$a->{'cachesize'} = 12345 ;
tie %y, 'DB_File', "filename", $flags, 0777, $a ; Несколько опций требуют дополнительного обсуждения. При использовании аналогичные ключи в C hash, compare и prefix хранят указатели на функции C. В DB_File эти ключи используются для хранения ссылок на Perl-подпрограммы. Ниже приведены шаблоны для каждой из подпрограмм:
sub hash
{
my ($data) = @_ ;
...
# return the hash value for $data
return $hash ;
}
sub compare
{
my ($key, $key2) = @_ ;
...
# return 0 if $key1 eq $key2
# -1 if $key1 lt $key2
# 1 if $key1 gt $key2
return (-1 , 0 or 1) ;
}
sub prefix
{
my ($key, $key2) = @_ ;
...
# return number of bytes of $key2 which are
# necessary to determine that it is greater than $key1
return $bytes ;
} См. «Изменение порядка сортировки BTREE» для примера использования шаблона compare.
Если вы используете интерфейс DB_RECNO и планируете использовать bval, ознакомьтесь с «Опция 'bval'».
Параметры по умолчанию
Можно опустить некоторые или все последние 4 параметра в вызове tie и позволить им принять значения по умолчанию. Поскольку DB_HASH является наиболее распространённым форматом файла, вызов:
tie %A, "DB_File", "filename" ; эквивалентен:
tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0666, $DB_HASH ; Также можно опустить параметр имени файла, поэтому вызов:
tie %A, "DB_File" ; эквивалентен:
tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ; См. "Внутрипамяти базы данных" для обсуждения использования undef вместо имени файла.
Внутрипамяти базы данных
Berkeley DB позволяет создавать базы данных в памяти, используя NULL (то есть, (char *)0 в C) вместо имени файла. DB_File использует undef вместо NULL для предоставления этой функциональности.
DB_HASH
Формат файла DB_HASH, вероятно, является наиболее часто используемым из трёх форматов файлов, поддерживаемых DB_File. Он также очень прост в использовании.
Простой пример
Этот пример показывает, как создать базу данных, добавить пары ключ/значение в базу данных, удалить пары ключ/значение и, наконец, как перечислить содержимое базы данных.
use warnings ;
use strict ;
use DB_File ;
our (%h, $k, $v) ;
unlink "fruit" ;
tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH
or die "Cannot open file 'fruit': $!\n";
# Add a few key/value pairs to the file
$h{"apple"} = "red" ;
$h{"orange"} = "orange" ;
$h{"banana"} = "yellow" ;
$h{"tomato"} = "red" ;
# Check for existence of a key
print "Banana Exists\n\n" if $h{"banana"} ;
# Delete a key/value pair.
delete $h{"apple"} ;
# print the contents of the file
while (($k, $v) = each %h)
{ print "$k -> $v\n" }
untie %h ; вот вывод:
Banana Exists
orange -> orange
tomato -> red
banana -> yellow Обратите внимание, что, как и в обычных ассоциативных массивах, порядок полученных ключей имеет случайный порядок.
DB_BTREE
Формат DB_BTREE полезен, когда вы хотите хранить данные в заданном порядке. По умолчанию ключи будут храниться в лексикографическом порядке, но, как вы увидите из примера, показанного в следующем разделе, очень легко определить собственную функцию сортировки.
Изменение порядка сортировки BTREE
Этот скрипт показывает, как переопределить алгоритм сортировки по умолчанию, используемый BTREE. Вместо использования обычного лексикографического упорядочения, будет использована функция сравнения, не учитывающая регистр.
use warnings ;
use strict ;
use DB_File ;
my %h ;
sub Compare
{
my ($key1, $key2) = @_ ;
"\L$key1" cmp "\L$key2" ;
}
# specify the Perl sub that will do the comparison
$DB_BTREE->{'compare'} = \&Compare ;
unlink "tree" ;
tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open file 'tree': $!\n" ;
# Add a key/value pair to the file
$h{'Wall'} = 'Larry' ;
$h{'Smith'} = 'John' ;
$h{'mouse'} = 'mickey' ;
$h{'duck'} = 'donald' ;
# Delete
delete $h{"duck"} ;
# Cycle through the keys printing them in order.
# Note it is not necessary to sort the keys as
# the btree will have kept them in order automatically.
foreach (keys %h)
{ print "$_\n" }
untie %h ; Вот вывод из приведенного выше кода.
mouse
Smith
Wall Есть несколько моментов, которые следует учитывать, если вы хотите изменить порядок в базе данных BTREE:
-
Новая функция сравнения должна быть указана при создании базы данных.
-
Вы не можете изменить порядок после создания базы данных. Таким образом, вы должны использовать ту же функцию сравнения каждый раз при обращении к базе данных.
-
Дубликаты ключей полностью определяются функцией сравнения. В примере с игнорированием регистра ключи: «KEY» и «key» считались бы дубликатами, и присвоение второму перезаписывало бы первый. Если разрешены дубликаты (с флагом R_DUP, описанным ниже), в базе данных хранится только одна копия дублирующихся ключей — поэтому (снова с приведенным примером) присвоение трёх значений ключам: «KEY», «Key» и «key» оставит в базе данных только первый ключ: «KEY» со тремя значениями. В некоторых ситуациях это приводит к потере информации, поэтому следует тщательно создавать функции сравнения при необходимости. Например, вышеуказанная процедура сравнения может быть изменена, чтобы дополнительно проводить сравнение, учитывающее регистр, если два ключа равны при сравнении, не учитывающем регистр:
sub compare { my($key1, $key2) = @_; lc $key1 cmp lc $key2 || $key1 cmp $key2; }И теперь у вас будут дубликаты только тогда, когда ключи сами по себе действительно одинаковые. (Примечание: в версиях библиотеки db до ноября 1996 года такие дубликаты ключей сохранялись, так что можно было восстановить исходные ключи в наборах ключей, которые сравнивались как равные).
Обработка дублирующихся ключей
Тип файла BTREE необязательно позволяет одному ключу быть связанным с произвольным числом значений. Этот параметр включён путём установки элемента флагов $DB_BTREE в R_DUP при создании базы данных.
Возникают некоторые трудности при использовании связанного интерфейса хэша, если вы хотите манипулировать базой данных BTREE с дублирующими ключами. Рассмотрим этот код:
use warnings ;
use strict ;
use DB_File ;
my ($filename, %h) ;
$filename = "tree" ;
unlink $filename ;
# Enable duplicate records
$DB_BTREE->{'flags'} = R_DUP ;
tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
# Add some key/value pairs to the file
$h{'Wall'} = 'Larry' ;
$h{'Wall'} = 'Brick' ; # Note the duplicate key
$h{'Wall'} = 'Brick' ; # Note the duplicate key and value
$h{'Smith'} = 'John' ;
$h{'mouse'} = 'mickey' ;
# iterate through the associative array
# and print each key/value pair.
foreach (sort keys %h)
{ print "$_ -> $h{$_}\n" }
untie %h ; Вот вывод:
Smith -> John
Wall -> Larry
Wall -> Larry
Wall -> Larry
mouse -> mickey Как вы можете видеть, 3 записи были успешно созданы с ключом Wall — единственное, что, когда они извлекаются из базы данных, они, похоже, имеют одинаковое значение, а именно Larry. Проблема вызвана тем, как работает интерфейс ассоциативного массива. В основном, когда используется интерфейс ассоциативного массива для извлечения значения, связанного с данным ключом, он всегда извлекает только первое значение.
Хотя из приведенного выше кода это может быть не очевидно, интерфейс ассоциативного массива может быть использован для записи значений с дублирующимися ключами, но он не может использоваться для их повторного чтения из базы данных.
Способ решения этой проблемы заключается в использовании метода API Berkeley DB, называемого seq. Этот метод позволяет последовательно получать пары ключ/значение. См. "ИНТЕРФЕЙС API" для получения подробностей о методе seq и API в целом.
Вот приведенный выше скрипт, переписанный с использованием метода API seq.
use warnings ;
use strict ;
use DB_File ;
my ($filename, $x, %h, $status, $key, $value) ;
$filename = "tree" ;
unlink $filename ;
# Enable duplicate records
$DB_BTREE->{'flags'} = R_DUP ;
$x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
# Add some key/value pairs to the file
$h{'Wall'} = 'Larry' ;
$h{'Wall'} = 'Brick' ; # Note the duplicate key
$h{'Wall'} = 'Brick' ; # Note the duplicate key and value
$h{'Smith'} = 'John' ;
$h{'mouse'} = 'mickey' ;
# iterate through the btree using seq
# and print each key/value pair.
$key = $value = 0 ;
for ($status = $x->seq($key, $value, R_FIRST) ;
$status == 0 ;
$status = $x->seq($key, $value, R_NEXT) )
{ print "$key -> $value\n" }
undef $x ;
untie %h ; что выводит:
Smith -> John
Wall -> Brick
Wall -> Brick
Wall -> Larry
mouse -> mickey На этот раз мы получили все пары ключ/значение, включая несколько значений, связанных с ключом Wall.
Для упрощения работы с дублирующимися ключами, DB_File поставляется с несколькими служебными методами.
Метод get_dup()
Метод get_dup помогает в чтении дублирующих значений из баз данных BTREE. Метод может иметь следующие формы:
$count = $x->get_dup($key) ;
@list = $x->get_dup($key) ;
%list = $x->get_dup($key, 1) ; В скалярном контексте метод возвращает количество значений, связанных с ключом, $key.
В контексте списка он возвращает все значения, соответствующие $key. Обратите внимание, что значения будут возвращены в, по-видимому, случайном порядке.
В контексте списка, если второй параметр присутствует и имеет значение TRUE, метод возвращает ассоциативный массив. Ключи ассоциативного массива соответствуют значениям, которые совпали в BTREE, а значения массива — это количество раз, когда конкретное значение встречалось в BTREE.
Таким образом, предполагая созданную выше базу данных, мы можем использовать get_dup следующим образом:
use warnings ;
use strict ;
use DB_File ;
my ($filename, $x, %h) ;
$filename = "tree" ;
# Enable duplicate records
$DB_BTREE->{'flags'} = R_DUP ;
$x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
my $cnt = $x->get_dup("Wall") ;
print "Wall occurred $cnt times\n" ;
my %hash = $x->get_dup("Wall", 1) ;
print "Larry is there\n" if $hash{'Larry'} ;
print "There are $hash{'Brick'} Brick Walls\n" ;
my @list = sort $x->get_dup("Wall") ;
print "Wall => [@list]\n" ;
@list = $x->get_dup("Smith") ;
print "Smith => [@list]\n" ;
@list = $x->get_dup("Dog") ;
print "Dog => [@list]\n" ; и он выведет:
Wall occurred 3 times
Larry is there
There are 2 Brick Walls
Wall => [Brick Brick Larry]
Smith => [John]
Dog => [] Метод find_dup()
$status = $X->find_dup($key, $value) ; Этот метод проверяет существование определённой пары ключ/значение. Если пара существует, курсор остаётся направленным на пару, и метод возвращает 0. В противном случае метод возвращает ненулевое значение.
Предполагая базу данных из предыдущего примера:
use warnings ;
use strict ;
use DB_File ;
my ($filename, $x, %h, $found) ;
$filename = "tree" ;
# Enable duplicate records
$DB_BTREE->{'flags'} = R_DUP ;
$x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
$found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
print "Larry Wall is $found there\n" ;
$found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ;
print "Harry Wall is $found there\n" ;
undef $x ;
untie %h ; выводит это
Larry Wall is there
Harry Wall is not there Метод del_dup()
$status = $X->del_dup($key, $value) ; Этот метод удаляет определённую пару ключ/значение. Он возвращает 0, если они существуют и были успешно удалены. В противном случае метод возвращает ненулевое значение.
Снова предполагая существование базы данных tree
use warnings ;
use strict ;
use DB_File ;
my ($filename, $x, %h, $found) ;
$filename = "tree" ;
# Enable duplicate records
$DB_BTREE->{'flags'} = R_DUP ;
$x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
$x->del_dup("Wall", "Larry") ;
$found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
print "Larry Wall is $found there\n" ;
undef $x ;
untie %h ; выводит это
Larry Wall is not there Сопоставление частичных ключей
Интерфейс BTREE имеет функцию, позволяющую сопоставлять частичные ключи. Эта функциональность только доступна, когда используется метод seq вместе с флагом R_CURSOR.
$x->seq($key, $value, R_CURSOR) ; Вот соответствующая цитата из страницы справки dbopen, где определено использование флага R_CURSOR с seq:
Note, for the DB_BTREE access method, the returned key is not
necessarily an exact match for the specified key. The returned key
is the smallest key greater than or equal to the specified key,
permitting partial key matches and range searches. В примере скрипта ниже подпрограмма match использует эту функцию для поиска и вывода первой соответствующей пары ключ/значение с учётом частичного ключа.
use warnings ;
use strict ;
use DB_File ;
use Fcntl ;
my ($filename, $x, %h, $st, $key, $value) ;
sub match
{
my $key = shift ;
my $value = 0;
my $orig_key = $key ;
$x->seq($key, $value, R_CURSOR) ;
print "$orig_key\t-> $key\t-> $value\n" ;
}
$filename = "tree" ;
unlink $filename ;
$x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
or die "Cannot open $filename: $!\n";
# Add some key/value pairs to the file
$h{'mouse'} = 'mickey' ;
$h{'Wall'} = 'Larry' ;
$h{'Walls'} = 'Brick' ;
$h{'Smith'} = 'John' ;
$key = $value = 0 ;
print "IN ORDER\n" ;
for ($st = $x->seq($key, $value, R_FIRST) ;
$st == 0 ;
$st = $x->seq($key, $value, R_NEXT) )
{ print "$key -> $value\n" }
print "\nPARTIAL MATCH\n" ;
match "Wa" ;
match "A" ;
match "a" ;
undef $x ;
untie %h ; Вот вывод:
IN ORDER
Smith -> John
Wall -> Larry
Walls -> Brick
mouse -> mickey
PARTIAL MATCH
Wa -> Wall -> Larry
A -> Smith -> John
a -> mouse -> mickey DB_RECNO
DB_RECNO предоставляет интерфейс к плоским текстовым файлам. Поддерживаются как переменные, так и фиксированные записи.
Для большей совместимости с Perl, смещение массива для всех массивов RECNO начинается с 0, а не с 1, как в Berkeley DB.
Как и в обычных массивах Perl, к массиву RECNO можно обратиться с помощью отрицательных индексов. Индекс -1 относится к последнему элементу массива, -2 — к предпоследнему и так далее. Попытка получить доступ к элементу до начала массива вызовет ошибку времени выполнения.
Параметр 'bval'
Работа параметра bval заслуживает обсуждения. Вот определение bval из страницы справки Berkeley DB 1.85 recno:
The delimiting byte to be used to mark the end of a
record for variable-length records, and the pad charac-
ter for fixed-length records. If no value is speci-
fied, newlines (``\n'') are used to mark the end of
variable-length records and fixed-length records are
padded with spaces. Второе предложение неверно. На самом деле bval будет по умолчанию равен "\n" только когда параметр openinfo в dbopen равен NULL. Если используется параметр openinfo, отличное от NULL, значение, которое случайно находится в bval, будет использовано. Это означает, что вы всегда должны указывать bval при использовании любого из параметров в параметре openinfo. Эта ошибка в документации будет исправлена в следующей версии Berkeley DB.
Это проясняет ситуацию в отношении самого Berkeley DB. Что насчет DB_File? Ну, поведение, определенное в цитате выше, довольно полезно, поэтому DB_File соответствует ему.
Это означает, что вы можете указывать другие параметры (например, cachesize) и при этом bval по умолчанию равен "\n" для записей переменной длины и места для записей фиксированной длины.
Также обратите внимание, что параметр bval позволяет указать только один байт в качестве разделителя.
Простой пример
Вот простой пример, который использует RECNO (если вы используете версию Perl ранее, чем 5.004_57, этот пример не будет работать — см. "Дополнительные методы RECNO" для обходного решения).
use warnings ;
use strict ;
use DB_File ;
my $filename = "text" ;
unlink $filename ;
my @h ;
tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_RECNO
or die "Cannot open file 'text': $!\n" ;
# Add a few key/value pairs to the file
$h[0] = "orange" ;
$h[1] = "blue" ;
$h[2] = "yellow" ;
push @h, "green", "black" ;
my $elements = scalar @h ;
print "The array contains $elements entries\n" ;
my $last = pop @h ;
print "popped $last\n" ;
unshift @h, "white" ;
my $first = shift @h ;
print "shifted $first\n" ;
# Check for existence of a key
print "Element 1 Exists with value $h[1]\n" if $h[1] ;
# use a negative index
print "The last element is $h[-1]\n" ;
print "The 2nd last element is $h[-2]\n" ;
untie @h ; Вот вывод из скрипта:
The array contains 5 entries
popped black
shifted white
Element 1 Exists with value blue
The last element is green
The 2nd last element is yellow Дополнительные методы RECNO
Если вы используете версию Perl ранее, чем 5.004_57, интерфейс связанного массива довольно ограничен. В приведенном выше примере скрипта push, pop, shift, unshift или определение длины массива не будут работать с связанным массивом.
Для повышения удобства интерфейса для более старых версий Perl, с DB_File поставляется ряд методов для имитации отсутствующих операций с массивами. Все эти методы доступны через объект, возвращаемый из вызова tie.
Вот эти методы:
- $X->push(list) ;
-
Добавляет элементы
listв конец массива. - $value = $X->pop ;
-
Удаляет и возвращает последний элемент массива.
- $X->shift
-
Удаляет и возвращает первый элемент массива.
- $X->unshift(list) ;
-
Добавляет элементы
listв начало массива. - $X->length
-
Возвращает количество элементов в массиве.
- $X->splice(offset, length, elements);
-
Возвращает срез массива.
Еще один пример
Вот более полный пример, который использует некоторые из описанных выше методов. Он также напрямую использует интерфейс API (см. "ИНТЕРФЕЙС API").
use warnings ;
use strict ;
my (@h, $H, $file, $i) ;
use DB_File ;
use Fcntl ;
$file = "text" ;
unlink $file ;
$H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0666, $DB_RECNO
or die "Cannot open file $file: $!\n" ;
# first create a text file to play with
$h[0] = "zero" ;
$h[1] = "one" ;
$h[2] = "two" ;
$h[3] = "three" ;
$h[4] = "four" ;
# Print the records in order.
#
# The length method is needed here because evaluating a tied
# array in a scalar context does not return the number of
# elements in the array.
print "\nORIGINAL\n" ;
foreach $i (0 .. $H->length - 1) {
print "$i: $h[$i]\n" ;
}
# use the push & pop methods
$a = $H->pop ;
$H->push("last") ;
print "\nThe last record was [$a]\n" ;
# and the shift & unshift methods
$a = $H->shift ;
$H->unshift("first") ;
print "The first record was [$a]\n" ;
# Use the API to add a new record after record 2.
$i = 2 ;
$H->put($i, "Newbie", R_IAFTER) ;
# and a new record before record 1.
$i = 1 ;
$H->put($i, "New One", R_IBEFORE) ;
# delete record 3
$H->del(3) ;
# now print the records in reverse order
print "\nREVERSE\n" ;
for ($i = $H->length - 1 ; $i >= 0 ; -- $i)
{ print "$i: $h[$i]\n" }
# same again, but use the API functions instead
print "\nREVERSE again\n" ;
my ($s, $k, $v) = (0, 0, 0) ;
for ($s = $H->seq($k, $v, R_LAST) ;
$s == 0 ;
$s = $H->seq($k, $v, R_PREV))
{ print "$k: $v\n" }
undef $H ;
untie @h ; и вот что он выводит:
ORIGINAL
0: zero
1: one
2: two
3: three
4: four
The last record was [four]
The first record was [zero]
REVERSE
5: last
4: three
3: Newbie
2: one
1: New One
0: first
REVERSE again
5: last
4: three
3: Newbie
2: one
1: New One
0: first Примечания:
-
Вместо итерации по массиву,
@hтак:foreach $i (@h)необходимо использовать либо это:
foreach $i (0 .. $H->length - 1)либо это:
for ($a = $H->get($k, $v, R_FIRST) ; $a == 0 ; $a = $H->get($k, $v, R_NEXT) ) -
Обратите внимание, что в обоих случаях при использовании метода
putиндекс записи указывался с помощью переменной,$i, а не с использованием собственного значения. Это происходит потому, чтоputвозвращает номер записи вставленной строки через этот параметр.
Интерфейс API
Помимо доступа к Berkeley DB с помощью связанного хэша или массива, также можно напрямую использовать большинство функций API, определённых в документации Berkeley DB.
Для этого необходимо сохранить копию объекта, возвращённого из связывания.
$db = tie %hash, "DB_File", "filename" ; После этого можно получить доступ к функциям API Berkeley DB как к методам DB_File напрямую, как показано ниже:
$db->put($key, $value, R_NOOVERWRITE) ; Важно: Если вы сохранили копию объекта, возвращённого из tie, подлежащий файлу базы данных не будет закрыт, пока переменная связывания не будет разъединена, и все копии сохранённого объекта не будут уничтожены.
use DB_File ;
$db = tie %hash, "DB_File", "filename"
or die "Cannot tie filename: $!" ;
...
undef $db ;
untie %hash ; См. "The untie() Gotcha" для получения более подробной информации.
Доступны все функции, определённые в dbopen, за исключением close() и dbopen() самого себя. Интерфейс методов DB_File для поддерживаемых функций был реализован таким образом, чтобы отражать работу Berkeley DB, насколько это возможно. Обратите особое внимание на следующее:
-
Методы возвращают значение статуса. Все возвращают 0 при успехе. Все возвращают -1, чтобы указать ошибку, и устанавливают
$!в точное кодовое значение ошибки. Возвращаемое значение 1 в целом (но не всегда) означает, что указанный ключ не существовал в базе данных.Определены и другие возвращаемые значения. Подробную информацию см. ниже и в документации Berkeley DB. Документация Berkeley DB должна использоваться в качестве основного источника.
-
Всякий раз, когда функция Berkeley DB возвращает данные через один из своих параметров, эквивалентный метод DB_File делает точно то же самое.
-
При внимательном подходе возможно смешивание вызовов API с интерфейсом связанного хэша/массива в одном фрагменте кода. Хотя лишь несколько методов, используемых для реализации интерфейса связывания, в настоящее время используют курсор, вы всегда должны предполагать, что курсор был изменён всякий раз, когда использовался интерфейс связанного хэша/массива. Например, этот код, вероятно, не сделает того, чего вы ожидаете:
$X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE or die "Cannot tie $filename: $!" ; # Get the first key/value pair and set the cursor $X->seq($key, $value, R_FIRST) ; # this line will modify the cursor $count = scalar keys %x ; # Get the second key/value pair. # oops, it didn't, it got the last key/value pair! $X->seq($key, $value, R_NEXT) ;Код выше можно перестроить, чтобы обойти проблему, как показано ниже:
$X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE or die "Cannot tie $filename: $!" ; # this line will modify the cursor $count = scalar keys %x ; # Get the first key/value pair and set the cursor $X->seq($key, $value, R_FIRST) ; # Get the second key/value pair. # worked this time. $X->seq($key, $value, R_NEXT) ;
Доступны также все константы, определённые в dbopen для использования в параметрах флагов в методах, определённых ниже. Для точного значения значений флагов обратитесь к документации Berkeley DB.
Ниже приведён список доступных методов.
- $status = $X->get($key, $value [, $flags]) ;
-
Используя ключ (
$key), этот метод считывает связанное с ним значение из базы данных. Считанное из базы данных значение возвращается в параметре$value.Если ключ не существует, метод возвращает 1.
В настоящее время для этого метода не определены флаги.
- $status = $X->put($key, $value [, $flags]) ;
-
Сохраняет пару ключ/значение в базе данных.
Если используется либо флаг R_IAFTER, либо R_IBEFORE, параметр
$keyбудет содержать номер записи вставленной пары ключ/значение.Допустимые флаги: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE и R_SETCURSOR.
- $status = $X->del($key [, $flags]) ;
-
Удаляет все пары ключ/значение с ключом
$keyиз базы данных.Возвращаемое значение 1 означает, что запрашиваемый ключ не был найден в базе данных.
В настоящее время единственный допустимый флаг — R_CURSOR.
- $status = $X->fd ;
-
Возвращает дескриптор файла для подлежащей базы данных.
См. "Locking: The Trouble with fd" для объяснения причин, по которым не следует использовать
fdдля блокировки базы данных. - $status = $X->seq($key, $value, $flags) ;
-
Этот интерфейс позволяет последовательно извлекать данные из базы данных. Подробную информацию см. в dbopen.
Параметры
$keyи$valueбудут установлены в пару ключ/значение, прочитанную из базы данных.Параметр флагов является обязательным. Допустимые значения флагов: R_CURSOR, R_FIRST, R_LAST, R_NEXT и R_PREV.
- $status = $X->sync([$flags]) ;
-
Очищает любые кэшированные буферы на диск.
В настоящее время единственный допустимый флаг — R_RECNOSYNC.
Фильтры DBM
Фильтр DBM — это фрагмент кода, используемый для всегда применения одного и того же преобразования ко всем ключам и/или значениям в базе данных DBM. Например, это необходимо, если вам нужно закодировать данные в UTF-8 перед записью в базу данных, а затем декодировать UTF-8 при чтении из файла базы данных.
Существует два способа использования фильтра DBM.
-
Использование API низкого уровня, определённого ниже.
-
Использование модуля DBM_Filter. Этот модуль скрывает сложность API, определённого ниже, и поставляется с несколькими «готовыми» фильтрами, которые охватывают некоторые общие случаи использования.
Рекомендуется использовать модуль DBM_Filter.
API фильтра DBM низкого уровня
С фильтрами DBM связано четыре метода. Все они работают одинаково, и каждый используется для установки (или отключения) одного фильтра DBM. Каждый ожидает один параметр — ссылку на подпрограмму. Разница между ними заключается только в том, где устанавливается фильтр.
Вкратце:
- filter_store_key
-
Если фильтр установлен с помощью этого метода, он будет вызываться каждый раз при записи ключа в базу данных DBM.
- filter_store_value
-
Если фильтр установлен с помощью этого метода, он будет вызываться каждый раз при записи значения в базу данных DBM.
- filter_fetch_key
-
Если фильтр установлен с помощью этого метода, он будет вызываться каждый раз при чтении ключа из базы данных DBM.
- filter_fetch_value
-
Если фильтр установлен с помощью этого метода, он будет вызываться каждый раз при чтении значения из базы данных DBM.
Можно использовать любое сочетание методов, от отсутствия до всех четырёх.
Все методы фильтра возвращают существующий фильтр, если он присутствует, или undef в противном случае.
Для удаления фильтра передайте undef ему.
Фильтр
Когда Perl вызывает каждый фильтр, локальная копия $_ будет содержать ключ или значение, которые необходимо отфильтровать. Фильтрация достигается путём изменения содержимого $_. Возвращаемое значение фильтра игнорируется.
Пример — проблема завершения нулём.
Рассмотрим следующий сценарий. У вас есть база данных DBM, которую вам нужно поделиться с приложением на C от стороннего разработчика. Приложение на C предполагает, что все ключи и значения завершаются нулём. К сожалению, когда Perl записывает в базы данных DBM, он не использует завершение нулём, поэтому вашему приложению Perl придётся самостоятельно управлять завершением нулём. При записи в базу данных вам придётся использовать что-то вроде этого:
$hash{"$key\0"} = "$value\0" ; Аналогично, при рассмотрении длины существующих ключей/значений необходимо учитывать нуль.
Гораздо лучше было бы игнорировать проблему завершения нулём в основном коде приложения и иметь механизм, который автоматически добавлял бы завершающий нуль ко всем ключам и значениям при записи в базу данных и удалял бы их при чтении из базы данных. Как вы, наверное, уже догадались, эту проблему очень легко решить с помощью фильтров DBM.
use warnings ;
use strict ;
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" ;
# Install DBM Filters
$db->filter_fetch_key ( sub { s/\0$// } ) ;
$db->filter_store_key ( sub { $_ .= "\0" } ) ;
$db->filter_fetch_value( sub { s/\0$// } ) ;
$db->filter_store_value( sub { $_ .= "\0" } ) ;
$hash{"abc"} = "def" ;
my $a = $hash{"ABC"} ;
# ...
undef $db ;
untie %hash ; Надеемся, что содержимое каждого фильтра будет самоочевидным. Оба фильтра «чтения» удаляют завершающий нуль, а оба фильтра «записи» добавляют завершающий нуль.
Ещё один пример — ключ является целым числом C.
Вот ещё один пример из реальной жизни. По умолчанию, когда Perl записывает в базу данных DBM, он всегда записывает ключ и значение в виде строк. Поэтому когда вы используете это:
$hash{12345} = "something" ; ключ 12345 будет сохранён в базе данных DBM как строка длиной 5 байт "12345". Если вы хотите, чтобы ключ хранился в базе данных DBM как целое число C, вам нужно использовать pack при записи и unpack при чтении.
Вот фильтр DBM, который это делает:
use warnings ;
use strict ;
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 ; На этот раз использовались только два фильтра — нам нужно было манипулировать только содержимым ключа, поэтому не было необходимости устанавливать какие-либо фильтры для значений.
Подсказки и советы
Блокировка: Проблема с fd
До версии 1.72 этого модуля рекомендованный метод блокировки баз данных DB_File заключался в использовании flock для дескриптора файла, возвращённого функцией «fd». К сожалению, этот метод оказался принципиально неверным (спасибо Дэвиду Харрису за выявление этой проблемы). Используйте его на свой страх и риск!
Методика блокировки выглядела так.
$db = tie(%db, 'DB_File', 'foo.db', O_CREAT|O_RDWR, 0644)
|| die "dbcreat foo.db $!";
$fd = $db->fd;
open(DB_FH, "+<&=$fd") || die "dup $!";
flock (DB_FH, LOCK_EX) || die "flock: $!";
...
$db{"Tom"} = "Jerry" ;
...
flock(DB_FH, LOCK_UN);
undef $db;
untie %db;
close(DB_FH); Проще говоря, происходит следующее:
-
Используйте «связывание» для открытия базы данных.
-
Заблокируйте базу данных с помощью fd и flock.
-
Читаем и записываем в базу данных.
-
Разблокируйте и закройте базу данных.
Суть проблемы заключается в том, что побочным эффектом открытия базы данных DB_File на шаге 2 является чтение начального блока из базы данных и его кэширование в памяти.
Чтобы понять, почему это проблема, представьте, что два процесса, скажем, «A» и «B», оба хотят обновить одну и ту же базу данных DB_File, используя описанные выше шаги блокировки. Предположим, процесс «A» уже открыл базу данных и имеет запись блокировки, но ещё не обновил базу данных (он завершил шаг 2, но ещё не начал шаг 3). Теперь процесс «B» пытается открыть ту же базу данных — шаг 1 будет успешным, но он заблокируется на шаге 2, пока процесс «A» не освободит блокировку. Важно отметить, что в этот момент времени оба процесса кэшируют идентичные начальные блоки из базы данных.
Теперь процесс «A» обновляет базу данных и случайно изменяет некоторые данные, содержащиеся в начальном буфере. Процесс «A» завершается, очищает все данные из кэша на диск и освобождает блокировку базы данных. В этот момент база данных на диске правильно отразит изменения, внесённые процессом «A».
После освобождения блокировки процесс «B» может продолжить работу. Он также обновляет базу данных и, к сожалению, также изменяет данные, которые были в его начальном буфере. После записи этих данных на диск они перезапишут некоторые/все изменения, внесённые процессом «A» в базу данных.
Результат этого сценария в лучшем случае — база данных, которая не содержит ожидаемых данных. В худшем случае база данных будет повреждена.
Вышеописанное не произойдёт каждый раз, когда конкурирующий процесс обновляет ту же базу данных DB_File, но это иллюстрирует, почему этот метод не следует использовать.
Безопасные способы блокировки базы данных
Начиная с версии 2.x, Berkeley DB имеет встроенную поддержку блокировок. Сопутствующий модуль, BerkeleyDB, предоставляет интерфейс к этой функциональности блокировок. Если вы серьёзно подходите к блокировке баз данных Berkeley DB, настоятельно рекомендую использовать BerkeleyDB.
Если использование BerkeleyDB не подходит, на CPAN доступно несколько модулей, которые можно использовать для реализации блокировки. Каждый модуль реализует блокировку по-разному и имеет разные цели. Поэтому важно понимать различия, чтобы выбрать подходящий для вашего приложения модуль. Вот три обёртки для блокировок:
- Tie::DB_Lock
-
Обёртка для DB_File, которая создаёт копии файла базы данных для чтения, обеспечивая своего рода многоверсионную систему параллельного чтения. Однако обновления всё равно выполняются последовательно. Используйте для баз данных, где чтение может быть длительным и могут возникнуть проблемы с согласованностью.
- Tie::DB_LockFile
-
Обёртка для DB_File, которая позволяет блокировать и разблокировать базу данных во время её использования. Избегает проблемы tie-before-flock, просто повторно привязывая базу данных при получении или снятии блокировки. Благодаря гибкости снятия и повторного получения блокировки в середине сеанса, это можно адаптировать к системе, которая будет работать с длительными обновлениями и/или чтением, если приложение следует подсказкам в документации POD.
- DB_File::Lock
-
Крайне лёгкая обёртка для DB_File, которая просто устанавливает блокировку файла до привязки базы данных и снимает блокировку после отвязки. Позволяет использовать один и тот же файл блокировки для нескольких баз данных, чтобы избежать тупиков, если это необходимо. Используйте для баз данных, где обновления и чтение быстры и просты, а семантика блокировки flock достаточна.
Совместное использование баз данных с приложениями на C
Нет технических причин, по которым база данных Berkeley DB не может быть совмещена как с приложением на Perl, так и с приложением на C.
Большинство проблем, о которых сообщают в этой области, сводятся к тому, что строки C завершаются нулём, а строки Perl — нет. См. "DBM FILTERS" для универсального способа решения этой проблемы.
Вот реальный пример. Netscape 2.0 сохраняет запись о посещённых вами местах и времени последнего посещения в базе данных DB_HASH. Обычно она хранится в файле ~/.netscape/history.db. Поле ключа в базе данных — строка расположения, а значение — время последнего посещения, хранящееся как 4-байтовое двоичное значение.
Если вы ещё не догадались, строка расположения хранится с завершающим нулём. Это означает, что вы должны быть осторожны при доступе к базе данных.
Вот фрагмент кода, основанный на скрипте ggh Тома Кристиана (доступен в вашем ближайшем архиве CPAN в authors/id/TOMC/scripts/nshist.gz).
use warnings ;
use strict ;
use DB_File ;
use Fcntl ;
my ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ;
$dotdir = $ENV{HOME} || $ENV{LOGNAME};
$HISTORY = "$dotdir/.netscape/history.db";
tie %hist_db, 'DB_File', $HISTORY
or die "Cannot open $HISTORY: $!\n" ;;
# Dump the complete database
while ( ($href, $binary_time) = each %hist_db ) {
# remove the terminating NULL
$href =~ s/\x00$// ;
# convert the binary time into a user friendly string
$date = localtime unpack("V", $binary_time);
print "$date $href\n" ;
}
# check for the existence of a specific key
# remember to add the NULL
if ( $binary_time = $hist_db{"http://mox.perl.com/\x00"} ) {
$date = localtime unpack("V", $binary_time) ;
print "Last visited mox.perl.com on $date\n" ;
}
else {
print "Never visited mox.perl.com\n"
}
untie %hist_db ; Особенности untie()
Если вы используете API Berkeley DB, настоятельно рекомендуется прочитать "The untie Gotcha" in perltie.
Даже если вы сейчас не используете интерфейс API, стоит его прочитать.
Вот пример, иллюстрирующий проблему с точки зрения DB_File:
use DB_File ;
use Fcntl ;
my %x ;
my $X ;
$X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_TRUNC
or die "Cannot tie first time: $!" ;
$x{123} = 456 ;
untie %x ;
tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
or die "Cannot tie second time: $!" ;
untie %x ; При запуске скрипт выдаст это сообщение об ошибке:
Cannot tie second time: Invalid argument at bad.file line 14. Хотя сообщение об ошибке выше относится ко второму оператору tie() в скрипте, источник проблемы заключается действительно в операторе untie(), который ему предшествует.
Прочитав perltie, вы, вероятно, уже догадались, что ошибка вызвана дополнительной копией привязанного объекта, хранящегося в $X. Если вы этого не сделали, то проблема заключается в том, что деструктор DB_File, DESTROY, не будет вызван, пока не будут уничтожены все ссылки на привязанный объект. Переменная привязки %x и $X выше содержат ссылку на объект. Вызов untie() уничтожит первую, но $X всё ещё содержит действительную ссылку, поэтому деструктор не будет вызван, и файл базы данных tst.fil останется открытым. Тот факт, что Berkeley DB затем сообщает об попытке открыть уже открытую базу данных посредством обобщённого сообщения об ошибке "Недопустимый аргумент", не помогает.
Если вы запустите скрипт со флагом -w, сообщение об ошибке станет:
untie attempted while 1 inner references still exist at bad.file line 12.
Cannot tie second time: Invalid argument at bad.file line 14. что указывает на реальную проблему. Наконец, скрипт можно изменить, чтобы исправить исходную проблему, уничтожив объект API перед untie:
...
$x{123} = 456 ;
undef $X ;
untie %x ;
$X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
... ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Почему в моей базе данных есть исходный код Perl?
Если вы посмотрите на содержимое файла базы данных, созданного DB_File, иногда в нём может быть часть скрипта Perl.
Это происходит потому, что Berkeley DB использует динамическую память для выделения буферов, которые впоследствии будут записаны в файл базы данных. Поскольку память динамическая, она могла использоваться для чего угодно до того, как DB её выделил. Так как Berkeley DB не очищает память после её выделения, неиспользуемые части будут содержать случайный мусор. В случае, когда скрипт Perl записывается в базу данных, случайный мусор будет соответствовать области динамической памяти, которая случайно использовалась во время компиляции скрипта.
Если вас не беспокоит возможность вставки частей ваших скриптов Perl в файл базы данных, то беспокоиться не о чем.
Как хранить сложные структуры данных с DB_File?
Хотя DB_File не может сделать это напрямую, есть модуль, который может прозрачно наслоиться на DB_File для достижения этой цели.
Обратите внимание на модуль MLDBM, доступный на CPAN в каталоге modules/by-module/MLDBM.
Что означает «широкий символ в записи подпрограммы»?
Обычно вы получите это сообщение, если работаете с данными UTF-8 и хотите читать/записывать их из/в файл базы данных Berkeley DB.
Самый простой способ решения этой проблемы — использование предопределённого фильтра «utf8» DBM_Filter (см. DBM_Filter), разработанного для решения этой ситуации.
Пример ниже показывает, что вам нужно, если и ключ, и значение должны быть в UTF-8.
use DB_File;
use DBM_Filter;
my $db = tie %h, 'DB_File', '/tmp/try.db', O_CREAT|O_RDWR, 0666, $DB_BTREE;
$db->Filter_Key_Push('utf8');
$db->Filter_Value_Push('utf8');
my $key = "\N{LATIN SMALL LETTER A WITH ACUTE}";
my $value = "\N{LATIN SMALL LETTER E WITH ACUTE}";
$h{ $key } = $value; Что означает «Недопустимый аргумент»?
Вы получите это сообщение об ошибке, когда один из параметров в вызове tie неверен. К сожалению, параметров довольно много, так что определить, какой именно неверен, может быть сложно.
Вот несколько возможностей:
-
Попытка повторного открытия базы данных без её закрытия.
-
Использование флага O_WRONLY.
Что означает «Не разрешено неприводимое имя 'DB_File'»?
Вы столкнётесь с этой ошибкой, когда у вас включена директива strict 'subs' (или полная директива strict) в вашем скрипте. Рассмотрим этот скрипт:
use warnings ;
use strict ;
use DB_File ;
my %x ;
tie %x, DB_File, "filename" ; Запуск этого скрипта вызовет указанную ошибку:
Bareword "DB_File" not allowed while "strict subs" in use Чтобы обойти ошибку, поместите слово DB_File в одинарные или двойные кавычки, как в этом примере:
tie %x, "DB_File", "filename" ; Хотя это может показаться настоящей проблемой, это действительно стоит усилий, чтобы иметь use strict во всех ваших скриптах.
СПРАВКИ
Статьи, которые либо посвящены DB_File, либо используют его.
-
Полнотекстовый поиск в Perl, Тим Кинтцле (tkientzle@ddj.com), Dr. Dobb's Journal, выпуск 295, январь 1999 г., стр. 34-41
ИСТОРИЯ
Перемещено в файл изменений.
ОШИБКИ
В некоторых старых версиях Berkeley DB были проблемы с записями фиксированной длины, использующими формат файла RECNO. Эта проблема была исправлена с версии 1.85 Berkeley DB.
Я уверен, что в коде есть ошибки. Если вы найдёте какие-либо ошибки или сможете предложить какие-либо улучшения, ваши комментарии будут приветствоваться.
ПОДДЕРЖКА
Общие отзывы, вопросы и сообщения об ошибках следует отправлять по адресу https://github.com/pmqs/DB_File/issues (желательно) или https://rt.cpan.org/Public/Dist/Display.html?Name=DB_File.
ДОСТУПНОСТЬ
DB_File поставляется со стандартным дистрибутивом исходного кода Perl. Посмотрите в каталог ext/DB_File. Учитывая промежуток времени между выпусками Perl, версия, поставляемая с Perl, скорее всего, устарела, поэтому последнюю версию всегда можно найти на CPAN (см. "CPAN" in perlmodlib для получения подробностей), в каталоге modules/by-module/DB_File.
DB_File предназначен для работы с любой версией Berkeley DB, но ограничен функциональностью, предоставляемой версией 1. Если вы хотите использовать новые возможности, доступные в Berkeley DB 2.x или более поздних версиях, используйте модуль Perl BerkeleyDB вместо этого.
Официальный веб-сайт Berkeley DB находится по адресу http://www.oracle.com/technology/products/berkeley-db/db/index.html. Там доступны все версии Berkeley DB.
В качестве альтернативы, Berkeley DB версии 1 доступна в вашем ближайшем архиве CPAN в src/misc/db.1.85.tar.gz.
АВТОРСКИЕ ПРАВА
Авторские права (c) 1995-2020 Пол Маркесс. Все права защищены. Эта программа является свободной программой; вы можете перераспределять её и/или изменять её в соответствии с теми же условиями, что и сам Perl.
Хотя DB_File покрывается лицензией Perl, библиотека, которую он использует, а именно Berkeley DB, — нет. Berkeley DB имеет свои авторские права и свою лицензию. Пожалуйста, уделите время на её прочтение.
Вот несколько слов из часто задаваемых вопросов Berkeley DB (на http://www.oracle.com/technology/products/berkeley-db/db/index.html) относительно лицензии:
Do I have to license DB to use it in Perl scripts?
No. The Berkeley DB license requires that software that uses
Berkeley DB be freely redistributable. In the case of Perl, that
software is Perl, and not your scripts. Any Perl scripts that you
write are your property, including scripts that make use of
Berkeley DB. Neither the Perl license nor the Berkeley DB license
place any restriction on what you may do with them. Если у вас есть какие-либо сомнения относительно ситуации с лицензией, свяжитесь с авторами Berkeley DB или автором DB_File. См. "AUTHOR" для получения подробностей.
СМОТРИТЕ ТАКЖЕ
perl, dbopen(3), hash(3), recno(3), btree(3), perldbmfilter, DBM_Filter
АВТОР
Интерфейс DB_File был написан Полом Маркессом <pmqs@cpan.org>.
© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/DB_File