How to read a file from bottom to top in Ruby?

后端 未结 3 2031
灰色年华
灰色年华 2020-12-09 12:04

I\'ve been working on a log viewer for a Rails app and have found that I need to read around 200 lines of a log file from bottom to top instead of the default top to bottom.

3条回答
  •  我在风中等你
    2020-12-09 12:34

    The only correct way to do this that also works on enormous files is to read n bytes at a time from the end until you have the number of lines that you want. This is essentially how Unix tail works.

    An example implementation of IO#tail(n), which returns the last n lines as an Array:

    class IO
      TAIL_BUF_LENGTH = 1 << 16
    
      def tail(n)
        return [] if n < 1
    
        seek -TAIL_BUF_LENGTH, SEEK_END
    
        buf = ""
        while buf.count("\n") <= n
          buf = read(TAIL_BUF_LENGTH) + buf
          seek 2 * -TAIL_BUF_LENGTH, SEEK_CUR
        end
    
        buf.split("\n")[-n..-1]
      end
    end
    

    The implementation is a little naive, but a quick benchmark shows what a ridiculous difference this simple implementation can already make (tested with a ~25MB file generated with yes > yes.txt):

                                user     system      total        real
    f.readlines[-200..-1]   7.150000   1.150000   8.300000 (  8.297671)
    f.tail(200)             0.000000   0.000000   0.000000 (  0.000367)
    

    The benchmark code:

    require "benchmark"
    
    FILE = "yes.txt"
    
    Benchmark.bmbm do |b|
      b.report "f.readlines[-200..-1]" do
        File.open(FILE) do |f|
          f.readlines[-200..-1]
        end
      end
    
      b.report "f.tail(200)" do
        File.open(FILE) do |f|
          f.tail(200)
        end
      end
    end
    

    Of course, other implementations already exist. I haven't tried any, so I cannot tell you which is best.

提交回复
热议问题