package TieFile; use Symbol; use strict; # The object constructed in TIEARRAY is a list, and these are the # fields my $F_OFFSETS = 0; # List of file seek offsets (for each line) my $F_FILEHANDLE = 1; # Open filehandle sub TIEARRAY { my ($pkg, $filename) = @_; my $fh = gensym(); open ($fh, $filename) || die "Could not open file: $!\n"; bless [ [0], # 0th line is at offset 0 $fh ], $pkg; } sub FETCH { my ($obj, $index) = @_; # Have we already read this line? my $rl_offsets = $obj->[$F_OFFSETS]; my $fh = $obj->[$F_FILEHANDLE]; if ($index > @$rl_offsets) { $obj->read_until ($index); } else { # seek to the appropriate file offset seek ($fh, $rl_offsets->[$index], 0); } scalar<$fh>; } sub STORE { die "Sorry. Cannot update file using package ListFile\n"; } sub DESTROY { my ($obj) = @_; # close the filehandle close($obj->[$F_FILEHANDLE]); } sub read_until { my ($obj, $index) = @_; my $rl_offsets = $obj->[$F_OFFSETS]; my $last_index = @$rl_offsets - 1; my $last_offset = $rl_offsets->[$last_index]; my $fh = $obj->[$F_FILEHANDLE]; seek ($fh, $last_offset, 0); my $buf; while (defined($buf = <$fh>)) { $last_offset += length($buf); $last_index++; push (@$rl_offsets, $last_offset); last if $last_index > $index; } } 1; if (!caller) { # Testing code my @list; # Map this file itself over @list tie @list, 'TieFile', 'TieFile.pm'; my $i; for ($i = 10; $i >= 0; --$i) { print "Line $i ", $list[$i]; } }