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

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

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

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

执行此操作的唯一正确方法也适用于大量文件,一次读取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 

实现有点天真,但快速基准测试显示了这个简单实现已经可以做出的荒谬差异(使用yes > yes.txt生成的~25MB文件进行测试):

  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) 

基准代码:

 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 

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

有一个Elif模块(Perl的File :: ReadBackwards的一个端口)可以高效地逐行向后读取文件。

由于我太新,不能评论molf真棒答案,我必须将其作为一个单独的答案发布。 我需要这个function来读取日志文件,并且日志的最后一部分包含我需要知道的字符串,我可以开始解析它。

因此,处理小型文件对我来说至关重要(我可能会在日志很小的时候ping日志)。 所以我增强了molf代码:

 class IO def tail(n) return [] if n < 1 if File.size(self) < ( 1 << 16 ) tail_buf_length = File.size(self) return self.readlines.reverse[0..n-1] else tail_buf_length = 1 << 16 end self.seek(-tail_buf_length,IO::SEEK_END) out = "" count = 0 while count <= n buf = self.read( tail_buf_length ) count += buf.count("\n") out += buf # 2 * since the pointer is a the end , of the previous iteration self.seek(2 * -tail_buf_length,IO::SEEK_CUR) end return out.split("\n")[-n..-1] end end