8.4.3 Discussion

The limitations of file access mentioned in this chapter's Introduction prevent reading a line at a time starting from
the end. You must read the lines into memory, then process them in
reverse order. This requires at least as much available memory as the
size of the file, unless you use tricks like Tie::File does.

The first technique moves through the array of lines in reverse
order. This destructively processes the array,
popping an element off the end of the array each time through the
loop. We could do it non-destructively with:

for ($i = $#lines; $i != -1; $i--) {
$line = $lines[$i];
}

The second approach generates an array of lines already in reverse
order. This array can then be processed non-destructively. We get the
reversed lines because the assignment to @lines
confers list context on the return from reverse,
and reverse confers list context on its argument
of <FILE>, which returns a list of all lines
in the file.

These approaches are easily extended to paragraphs just by changing
$/:

The Tie::File module lets you treat the file as an array of lines.
The solution then becomes simply iterating through the array a line
at a time from the end back to the start. It's much slower than
reading everything into memory and reversing it, but works on files
too big to fit into memory all at once. Be careful, though: Tie::File
will rewrite the file if you change the contents of the tied
@lines, so don't do that. In our example,
assigning @lines = reverse(@lines) would reverse
the file on disk! By opening the file with mode
O_RDONLY (0), you can avoid that possibility. The
default mode is O_RDWR | O_CREAT. Also, Tie::File
cannot emulate the paragraph semantics of setting
$/ to the empty string ("").

8.4.4 See Also

The reverse function in
perlfunc(1) and in Chapter 29 of
Programming Perl; the $/
entry in perlvar(1), and in Chapter 28 of
Programming Perl; the documentation for the
standard Tie::File module; Recipe 4.11;
Recipe 1.7