The final form of data manipulation that you can apply to flat-file databases is the removal, or deletion, of records from the database. We shall process the file a record at a time by passing the data through a temporary file, just as we did for updating, rather than slurping all the data into memory and dumping it at the end.
With this technique, the action of removing a record from the database is more an act of omission than any actual deletion. Each record is read in from the file, tested, and written out to the file. When the record to be deleted is encountered, it is simply not written to the temporary file. This effectively removes all trace of it from the database, albeit in a rather unsophisticated way.
The following program can be used to remove the relevant record from the delimited megalithic database when given an argument of the name of the site to delete:
#!/usr/bin/perl -w # # ch02/deletemegadata/deletemegadata: Deletes the record for the given # megalithic site. Uses # colon-separated data # ### Check the user has supplied an argument to scan for ### 1) The name of the file containing the data ### 2) The name of the site to delete die "Usage: deletemegadata <data file> <site name>\n" unless @ARGV == 2; my $megalithFile = $ARGV[0]; my $siteName = $ARGV[1]; my $tempFile = "tmp.$$"; ### Open the data file for reading, and die upon failure open MEGADATA, "<$megalithFile" or die "Can't open $megalithFile: $!\n"; ### Open the temporary megalith data file for writing open TMPMEGADATA, ">$tempFile" or die "Can't open temporary file $tempFile: $!\n"; ### Scan through all the entries for the desired site while ( <MEGADATA> ) { ### Extract the site name (the first field) from the record my ( $name ) = split( /:/, $_ ); ### Test the sitename against the record's name if ( $siteName eq $name ) { ### We've found the record to delete, so skip it and move to next record next; } ### Write the original record out to the temporary file print TMPMEGADATA $_ or die "Error writing $tempFile: $!\n"; } ### Close the megalith input data file close MEGADATA; ### Close the temporary megalith output data file close TMPMEGADATA or die "Error closing $tempFile: $!\n"; ### We now "commit" the changes by deleting the old file ... unlink $megalithFile or die "Can't delete old $megalithFile: $!\n"; ### and renaming the new file to replace the old one. rename $tempFile, $megalithFile or die "Can't rename '$tempFile' to '$megalithFile': $!\n"; exit 0;
The code to remove records from a fixed-length data file is almost identical. The only change is in the code to extract the field value, as you’d expect:
### Extract the site name (the first field) from the record my ( $name ) = unpack( "A64", $_ );
Like updating, deleting data may cause problems if multiple users are attempting to make simultaneous changes to the data. We’ll look at how to deal with this problem a little later in this chapter.