我一直在研究Rails应用程序的日志查看器,并且发现我需要从下到上阅读大约200行日志文件,而不是默认的从上到下。
日志文件可能会变得非常大,所以我已经尝试并排除了IO.readlines(“log_file.log”)[ - 200 ..- 1]方法。
有没有其他方法可以在Ruby中向后读取文件而无需插件或gem?
答案 0 :(得分: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
实现有点天真,但快速基准测试显示了这个简单实现已经可以做出的荒谬差异(使用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
当然,other implementations已经存在。我没有尝试过,所以我不能告诉你哪个是最好的。
答案 1 :(得分:3)
有一个模块Elif可用(Perl的File::ReadBackwards端口)可以高效地逐行向后读取文件。
答案 2 :(得分:1)
由于我太新,无法评论molf真棒答案,我必须将其作为一个单独的答案发布。 我需要这个功能来读取日志文件,并且日志的最后一部分包含我需要知道的字符串,我可以开始解析它。
因此处理小尺寸文件对我来说至关重要(我可能会在日志很小的时候对日志进行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