use XBase;
my $table = new XBase "dbase.dbf" or die XBase->errstr;
for (0 .. $table->last_record) {
my ($deleted, $id, $msg)
= $table->get_record($_, "ID", "MSG");
print "$id:\t$msg\n" unless $deleted;
}
The following methods are supported by XBase module:
The parameters can also be specified in the form of hash: value of name is then the name of the table, other flags supported are:
memofile specifies non standard name for the associated memo file. By default it's the name of the dbf file, with extension dbt or fpt.
ignorememo ignore memo file at all. This is usefull if you've lost the dbt file and you do not need it. Default is false.
memosep separator of memo records in the dBase III dbt files. The standard says it should be "\x1a\x1a". There are however implamentations that only put in one "\x1a". XBase.pm tries to guess which is valid for your dbt but if it fails, you can tell it yourself.
nolongchars prevents XBase to treat the decimal value of character fields as high byte of the length --- there are some broken products around producing character fields with decimal values set.
my $table = new XBase "table.dbf" or die XBase->errstr;
my $table = new XBase "name" => "table.dbf",
"ignorememo" => 1;
recompute_lastrecno forces XBase.pm to disbelieve the information about the number of records in the header of the dbf file and recompute the number of records. Use this only if you know that some other software of yours produces incorrect headers.
You can call this method as method of another XBase object and then you only need to pass name value of the hash; the structure (fields) of the new file will be the same as of the original object.
If you call create using class name (XBase), you have to (besides name) also specify another four values, each being a reference to list: field_names, field_types, field_lengths and field_decimals. The field types are specified by one letter strings (C, N, L, D, ...). If you set some value as undefined, create will make it into some reasonable default.
my $newtable = $table->create("name" => "copy.dbf");
my $newtable = XBase->create("name" => "copy.dbf",
"field_names" => [ "ID", "MSG" ],
"field_types" => [ "N", "C" ],
"field_lengths" => [ 6, 40 ],
"field_decimals" => [ 0, undef ]);
Other attributes are memofile for non standard memo file location, codepage to set the codepage flag in the dbf header (it does not affect how XBase.pm reads or writes the data though, just to make FoxPro happy), and version to force different version of the dbt (dbt) file. The default is the version of the object from which you create the new one, or 3 if you call this as class method (XBase->create).
The new file mustn't exist yet --- XBase will not allow you to overwrite existing table. Use drop (or unlink) to delete it first.
To explicitely delete/undelete a record, use methods delete_record or undelete_record with record number as a parameter.
Assorted examples of reading and writing:
my @data = $table->get_record(3, "jezek", "krtek");
my $hashref = $table->get_record_as_hash(38);
$table->set_record_hash(8, "jezek" => "jezecek",
"krtek" => 5);
$table->undelete_record(4);
This is a code to update field MSG in record where ID is 123.
use XBase;
my $table = new XBase "test.dbf" or die XBase->errstr;
for (0 .. $table->last_record) {
my ($deleted, $id) = $table->get_record($_, "ID")
die $table->errstr unless defined $deleted;
next if $deleted;
$table->update_record_hash($_, "MSG" => "New message")
if $id == 123;
}
Prepare will return object cursor, the following method are methods of the cursor, not of the table.
Examples of using cursors:
my $table = new XBase "names.dbf" or die XBase->errstr;
my $cursor = $table->prepare_select("ID", "NAME", "STREET");
while (my @data = $cursor->fetch) {
### do something here, like print "@data\n";
}
my $table = new XBase "employ.dbf";
my $cur = $table->prepare_select_with_index("empid.ndx");
## my $cur = $table->prepare_select_with_index(
["empid.cdx", "ADDRES", "char"], "id", "address");
$cur->find_eq(1097);
while (my $hashref = $cur->fetch_hashref
and $hashref->{"ID"} == 1097) {
### do something here with $hashref
}
The second example shows that after you have done find_eq, the fetches continue untill the end of the index, so you have to check whether you are still on records with given value. And if there is no record with value 1097 in the indexed field, you will just get the next record in the order.
The updating example can be rewritten to:
use XBase;
my $table = new XBase "test.dbf" or die XBase->errstr;
my $cursor = $table->prepare_select("ID")
while (my ($id) = $cursor->fetch) {
$table->update_record_hash($cursor->last_fetched,
"MSG" => "New message") if $id == 123
}
To print the content of the file in a readable form, use method dump_records. It prints all not deleted records from the file. By default, all fields are printed, separated by colons, one record on a row. The method can have parameters in a form of a hash with the following keys:
Example of use is
use XBase;
my $table = new XBase "table" or die XBase->errstr;
$table->dump_records("fs" => " | ", "rs" => " <-+\n",
"fields" => [ "id", "msg" ]);'
Also note that there is a script dbfdump.pl(1) that does the printing.
The method header_info returns (not prints) string with information about the file and about the fields.
Module XBase::Base(3) defines some basic functions that are inherited by both XBase and XBase::Memo(3) module.
If there is a memo field in the dbf file, the module tries to open file with the same name but extension dbt, fpt or smt. It uses module XBase::Memo(3) for this. It reads and writes this memo field transparently (you do not know about it) and returns the data as single scalar.
General locking methods are locksh, lockex and unlock for shared lock, exclusive lock and unlock. They call flock but you can redefine then in XBase::Base package.
http://www.e-bachmann.dk/docs/xbase.htm
All rights reserved. This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Special thanks go to Erik Bachmann for his great page about the file structures; to Frans van Loon, William McKee, Randy Kobes and Dan Albertsson for longtime cooperation and many emails we've exchanged when fixing and polishing the modules' behaviour; and to Dan Albertsson for providing support for the project.