A.4 Answers for Chapter 5

A.4.1 Exercise 1 (Section 5.8.1)

use Storable;

my $all = "**all machines**";
my $data_file = "total_bytes.data";

my %total_bytes;
if (-e $data_file) {
  my $data = retrieve $data_file;
  %total_bytes = %$data;

while (<>) {
  next if /^#/;
  my ($source, $destination, $bytes) = split;
  $total_bytes{$source}{$destination} += $bytes;
  $total_bytes{$source}{$all} += $bytes;

store \%total_bytes, $data_file;

### remainder of program is unchanged

This is similar to what you saw in Chapter 4, but now it uses Storable.

Near the top, put the filename into a variable. You can then retrieve the data but only if the data file already exists.

After reading the data, use Storable again to write it back out to the same disk file.

If you chose to write the hash's data to a file the hard way, by writing your own code and your own file format, you're working too hard. More to the point, unless you're extraordinarily talented or spend way too long on this exercise, you almost certainly have bugs in your serialization routines, or at least flaws in your file format.

A.4.2 Exercise 2 (Section 5.8.2)

There should probably be some checks to ensure that Storable was successful. It will catch some errors (and die), but it will simply return undef for some. See the documentation for Storable. (Of course, if you checked the return values from store and retrieve, you should give yourself extra credit on the previous exercise.)

The program should save the old data file (if any) under a backup filename so that it's easy to revert the latest additions. In fact, it could even keep several backups, such as the last week's worth.

It might also be nice to be able to print the output without having any new input data. As it's written, this can be done by giving an empty file (such as /dev/null) as the input. However there should be an easier way. The output functionality could be separated entirely from the updating, in fact.