Recipe 8.18 Treating a File as an Array

8.18.1 Problem

Your file contains a list of lines or records, and you'd like to be able to use Perl's powerful array operations to access and manipulate the file.

8.18.2 Solution

Use the Tie::File module, standard with v5.8 of Perl:

use Tie::File;
use Fcntl;

tie @data, Tie::File, $FILENAME or die "Can't tie to $filename : $!\n";
# use array operations on @data to work with the file

8.18.3 Discussion

The Tie::File module makes a file appear to be an array, one record per element. You can then fetch and assign to elements of the array, use array functions like push and splice, use negative indices, or reverse it, and in every instance you're really working with the data on disk.

If you don't specify how Tie::File should open the file, it is opened for read and write access and created if it doesn't exist. To specify a particular access mode (see Recipe 7.1), pass the Fcntl mode with the mode parameter when you tie. For example:

use Fcntl;
tie(@data, Tie::File, $filename, mode => O_RDONLY)
  or die "Can't open $filename for reading: $!\n";

When you alter the array, the file is rewritten on disk. For example, if you change the length of an element, all records later in the file must be copied to make the change. Take this code:

foreach (@data) {
  s/Perl Cookbook/Perl Cookbook (2nd edition)/g;

That's close because you change the length of record 0, forcing a copy of records 1..N. Then you change the length of record 1, forcing a copy of records 2..N. It's better to defer the update until all changes have been made and then have Tie::File update the file in one single write. To do this, call a method on the object behind the tied array:

(tied @data)->defer;                     # defer updates
foreach (@data) {
  s/Perl Cookbook/Perl Cookbook (2nd edition)/g;
(tied @data)->flush;

Exactly how much rewriting to defer is governed by how much memory you let Tie::File use, because the only way to keep track of changes without updating the file is to store those changes in memory. The Tie::File manpage shows how to change options for memory use.

8.18.4 See Also

Recipe 8.4; Recipe 8.8; Recipe 8.10