Updating a Random-Access File
Problem
You want to read in an old record from a binary file, change its values, and write back the record.
Solution
After reading the old record,
pack
up the updated values, seek to the previous
address, and write it back.
use Fcntl; # for SEEK_SET and SEEK_CUR
$ADDRESS = $RECSIZE * $RECNO;
seek(FH, $ADDRESS, SEEK_SET) or die "Seeking: $!";
read(FH, $BUFFER, $RECSIZE) == $RECSIZE
or die "Reading: $!";
@FIELDS = unpack($FORMAT, $BUFFER);
# update fields, then
$BUFFER = pack($FORMAT, @FIELDS);
seek(FH, -$RECSIZE, SEEK_CUR) or die "Seeking: $!";
print FH $BUFFER;
close FH or die "Closing: $!";Discussion
You don’t have to use anything fancier than
print in Perl to output a record. Remember that
the opposite of read is not
write but print, although oddly
enough, the opposite of sysread actually is
syswrite. (split and
join are opposites, but there’s no
speak to match listen, no
resurrect for kill, and no
curse for bless.)
The example program shown in Example 8.4, weekearly , takes one argument: the user whose record you want to backdate by a week. (Of course, in practice, you wouldn’t really want to (nor be able to!) mess with the system accounting files.) This program requires write access to the file to be updated, since it opens the file in update mode. After fetching and altering the record, it packs it up again, skips backwards in the file one record, and writes it out.
Example 8-4. weekearly
#!/usr/bin/perl # weekearly -- set someone's login date back ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access