FireBird34 has asked for the wisdom of the Perl Monks concerning the following question:

Is there anyway to read the output of a file from the end of the file to the beginning? Say if FILE had the following contents:

bob
bill
frank
george


I would want as my output:

george
frank
bill
bob

I know you can do this with modules, but is there a way to do it without having to use the module? (the server I'm uploading to doesn't have the module(s) built in, although if need be, it could be put in)

Replies are listed 'Best First'.
Re: File output from end to beginning
by dws (Chancellor) on Jan 18, 2003 at 05:29 UTC
    Is there anyway to read the output of a file from the end of the file to the beginning?

    If you can fit the file into memory, you can do something like

    print reverse <>;
Re: File output from end to beginning
by pg (Canon) on Jan 18, 2003 at 06:25 UTC
    This solution has been tested on both AIX and Win98. Its advantages are:
    1. only holds one line in memory, memory usage is the minimum
    2. only goes thru the file once, extreamly fast
    One key point to help understand the source code: read from the beginning to the end, and write from the end to the beginning.

    #usage perl -w test.pl oldfile newfile use Fcntl qw(SEEK_SET SEEK_END); use File::Copy; use strict; use constant NEWLINE_ADJUSTMENT => 0; #set this to 1 on Win98, 0 on un +ix! copy($ARGV[0], $ARGV[1]); open(AFILE, "<", $ARGV[0]); open(BFILE, "+<", $ARGV[1]); seek(AFILE, 0, SEEK_END); my $len = tell(AFILE); my $written_len = NEWLINE_ADJUSTMENT; seek(AFILE, 0, SEEK_SET); while (<AFILE>) { seek(BFILE, $len - $written_len - length(), SEEK_SET); $written_len += length() + NEWLINE_ADJUSTMENT; print BFILE; } close(AFILE); close(BFILE);
Re: File output from end to beginning
by graff (Chancellor) on Jan 18, 2003 at 05:34 UTC
    Well, if you're confident that file size won't cause a problem with memory consumption, you could do this:
    open( IN, "file" ); @lines = <IN>; close IN; print reverse @lines;
    On the other hand, if file size and memory constraints are an issue, you'd probably want to go through the file line by line, store the bytes offsets (from "tell()") for each, then do a loop consisting of: seek(); $_=<>; print(); going through the offsets in reverse order.
Re: File output from end to beginning
by Hofmator (Curate) on Jan 18, 2003 at 12:10 UTC
    There's also a module that does this (surprise :), File::ReadBackwards. From the synopsis:
    use File::ReadBackwards; tie *BW, File::ReadBackwards, 'log_file' or die "can't read 'log_file' $!"; print while <BW>;

    -- Hofmator

      Thanks all -- have it working =) Also, I tried that module (FILE::ReadBackwards), but the server (WinXP) doesn't have it installed, and supprisingly neither does my Linux box. Didn't want to put it on if it wasn't needed. Again, thanks =)