📄 db_file.pm
字号:
} # 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 ;Here is the output from the code above. mouse Smith WallThere are a few point to bear in mind if you want to change theordering in a BTREE database:=over 5=item 1.The new compare function must be specified when you create the database.=item 2.You cannot change the ordering once the database has been created. Thusyou must use the same compare function every time you access thedatabase.=item 3Duplicate keys are entirely defined by the comparison function.In the case-insensitive example above, the keys: 'KEY' and 'key'would be considered duplicates, and assigning to the second onewould overwrite the first. If duplicates are allowed for (with theR_DUP flag discussed below), only a single copy of duplicate keysis stored in the database --- so (again with example above) assigningthree values to the keys: 'KEY', 'Key', and 'key' would leave justthe first key: 'KEY' in the database with three values. For somesituations this results in information loss, so care should be takento provide fully qualified comparison functions when necessary.For example, the above comparison routine could be modified toadditionally compare case-sensitively if two keys are equal in thecase insensitive comparison: sub compare { my($key1, $key2) = @_; lc $key1 cmp lc $key2 || $key1 cmp $key2; }And now you will only have duplicates when the keys themselvesare truly the same. (note: in versions of the db library prior toabout November 1996, such duplicate keys were retained so it waspossible to recover the original keys in sets of keys thatcompared as equal).=back =head2 Handling Duplicate Keys The BTREE file type optionally allows a single key to be associatedwith an arbitrary number of values. This option is enabled by settingthe flags element of C<$DB_BTREE> to R_DUP when creating the database.There are some difficulties in using the tied hash interface if youwant to manipulate a BTREE database with duplicate keys. Consider thiscode: 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 ;Here is the output: Smith -> John Wall -> Larry Wall -> Larry Wall -> Larry mouse -> mickeyAs you can see 3 records have been successfully created with key C<Wall>- the only thing is, when they are retrieved from the database theyI<seem> to have the same value, namely C<Larry>. The problem is causedby the way that the associative array interface works. Basically, whenthe associative array interface is used to fetch the value associatedwith a given key, it will only ever retrieve the first value.Although it may not be immediately obvious from the code above, theassociative array interface can be used to write values with duplicatekeys, but it cannot be used to read them back from the database.The way to get around this problem is to use the Berkeley DB API methodcalled C<seq>. This method allows sequential access to key/valuepairs. See L<THE API INTERFACE> for details of both the C<seq> methodand the API in general.Here is the script above rewritten using the C<seq> API method. 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 ;that prints: Smith -> John Wall -> Brick Wall -> Brick Wall -> Larry mouse -> mickeyThis time we have got all the key/value pairs, including the multiplevalues associated with the key C<Wall>.To make life easier when dealing with duplicate keys, B<DB_File> comes with a few utility methods.=head2 The get_dup() MethodThe C<get_dup> method assists inreading duplicate values from BTREE databases. The method can take thefollowing forms: $count = $x->get_dup($key) ; @list = $x->get_dup($key) ; %list = $x->get_dup($key, 1) ;In a scalar context the method returns the number of values associatedwith the key, C<$key>.In list context, it returns all the values which match C<$key>. Notethat the values will be returned in an apparently random order.In list context, if the second parameter is present and evaluatesTRUE, the method returns an associative array. The keys of theassociative array correspond to the values that matched in the BTREEand the values of the array are a count of the number of times thatparticular value occurred in the BTREE.So assuming the database created above, we can use C<get_dup> likethis: 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" ;and it will print: Wall occurred 3 times Larry is there There are 2 Brick Walls Wall => [Brick Brick Larry] Smith => [John] Dog => []=head2 The find_dup() Method $status = $X->find_dup($key, $value) ;This method checks for the existence of a specific key/value pair. If thepair exists, the cursor is left pointing to the pair and the method returns 0. Otherwise the method returns a non-zero value.Assuming the database from the previous example: 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 ;prints this Larry Wall is there Harry Wall is not there=head2 The del_dup() Method $status = $X->del_dup($key, $value) ;This method deletes a specific key/value pair. It returns0 if they exist and have been deleted successfully.Otherwise the method returns a non-zero value.Again assuming the existence of the C<tree> database 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 ;prints this Larry Wall is not there=head2 Matching Partial Keys The BTREE interface has a feature which allows partial keys to bematched. This functionality is I<only> available when the C<seq> methodis used along with the R_CURSOR flag. $x->seq($key, $value, R_CURSOR) ;Here is the relevant quote from the dbopen man page where it definesthe use of the R_CURSOR flag with 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.In the example script below, the C<match> sub uses this feature to findand print the first matching key/value pair given a partial key. 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 ;Here is the output: IN ORDER Smith -> John Wall -> Larry Walls -> Brick mouse -> mickey PARTIAL MATCH Wa -> Wall -> Larry A -> Smith -> John a -> mouse -> mickey=head1 DB_RECNODB_RECNO provides an interface to flat text files. Both variable andfixed length records are supported.In order to make RECNO more compatible with Perl, the array offset forall RECNO arrays begins at 0 rather than 1 as in Berkeley DB.As with normal Perl arrays, a RECNO array can be accessed usingnegative indexes. The index -1 refers to the last element of the array,-2 the second last, and so on. Attempting to access an element beforethe start of the array will raise a fatal run-time error.=head2 The 'bval' OptionThe operation of the bval option warrants some discussion. Here is thedefinition of bval from the Berkeley DB 1.85 recno manual page: 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.The second sentence is wrong. In actual fact bval will only default toC<"\n"> when the openinfo parameter in dbopen is NULL. If a non-NULLopeninfo parameter is used at all, the value that happens to be in bvalwill be used. That means you always have to specify bval when makinguse of any of the options in the openinfo parameter. This documentationerror will be fixed in the next release of Berkeley DB.That clarifies the situation with regards Berkeley DB itself. Whatabout B<DB_File>? Well, the behavior defined in the quote above isquite useful, so B<DB_File> conforms to it.That means that you can specify other options (e.g. cachesize) andstill have bval default to C<"\n"> for variable length records, andspace for fixed length records.Also note that the bval option only allows you to specify a single byteas a delimiter.=head2 A Simple ExampleHere is a simple example that uses RECNO (if you are using a version of Perl earlier than 5.004_57 this example won't work -- see L<Extra RECNO Methods> for a workaround). use warnings ; use strict ; use DB_File ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -