in article gMmv6.3969$pS2.193227 / typhoon.mn.mediaone.net, Daniel Berger at
djberg96 / hotmail.com wrote on 3/25/01 5:54 AM:
> 
> I *do not* want to read the entire file into memory
>

Dan,

The following should do what you want (and handle at least some of the
pathologic conditions (e.g. linelength > buffersize)

Regards, Paul

# irb -r rev --prompt xmp
r = ReverseFile.new File.new '/var/log/messages'
    ==>#<ReverseFile io=#<File:0x81e46f4>>
r.reverseReadline
    ==>"Mar 25 21:37:18 norbert dhclient: DHCPREQUEST on ex0 to 192.168.1.1
port 67"
r.reverseReadline
    ==>"Mar 25 21:12:16 norbert dhclient: bound to 192.168.1.104 -- renewal
in 1502 seconds."
count = 0
    ==>0
r.reverseReadlines { count += 1 }
    ==>nil
count
    ==>257


===== rev.rb =====

class ReverseFile

    def initialize(io,readback=8000)
        raise RuntimeError, "readback must be >1" unless readback > 1
        @io = io
        @readback = readback
        @fpos = @io.stat.size
        @linebuf = readbuf
        return self
    end

    def reverseReadline
        @linebuf = readbuf if @linebuf == []
        if block_given?
            yield @linebuf.pop
        else
            return @linebuf.pop
        end
    end

    def reverseReadlines
        lins = []
        while (line=reverseReadline) != nil
            if block_given?
                yield line
            else
                lines << line
            end
        end
        return lines unless block_given?
    end

    def inspect
        "#<ReverseFile io=#{@io}>"
    end

    def readbuf
        seekpos = (@fpos-@readback)>0 ? (@fpos-@readback) : 0
        @io.seek seekpos
        newfpos = @io.pos
        lines = @io.read(@fpos-newfpos).split $/

        if newfpos == 0
            @fpos = 0
            return lines
        elsif lines.length <= 1
            @readback = @readback * 2
            return readbuf
        else
            firstline = lines.shift
            @fpos = newfpos + firstline.length
            return lines
        end
    end

    private :readbuf
end