如何在Ruby中从下到上读取文件?

eri*_*lli 13 ruby file-io ruby-on-rails

我一直在为Rails应用程序的日志查看器工作,并且发现我需要从下到上阅读大约200行日志文件,而不是默认的从上到下.

日志文件可能会变得非常大,所以我已经尝试并排除了IO.readlines("log_file.log")[ - 200 ..- 1]方法.

有没有其他方法可以在Ruby中向后读取文件而无需插件或gem?

mol*_*olf 17

执行此操作的唯一正确方法也适用于大量文件,一次读取n个字节,直到您拥有所需的行数.这基本上就是Unix的tail工作原理.

一个示例实现IO#tail(n),它返回最后n一行作为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
Run Code Online (Sandbox Code Playgroud)

实现有点天真,但快速基准测试显示这个简单实现已经可以做出的荒谬差异(使用生成的~25MB文件进行测试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)
Run Code Online (Sandbox Code Playgroud)

基准代码:

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
Run Code Online (Sandbox Code Playgroud)

当然,其他实现已经存在.我没有尝试过,所以我不能告诉你哪个是最好的.