2011-12-30 115 views
8

我有一个gzip文件,目前我读到这样的:如何逐行读取gzip文件?

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
output = gz.read 
puts result 

我觉得这个转换文件为一个字符串,但我想逐行读它。

我想完成的是该文件有一些垃圾警告消息,我想grep这些警告消息,然后将它们写入到另一个文件。但是,一些警告信息是重复的,所以我必须确保我只grep他们一次。因此,逐行阅读会帮助我。

回答

17

你应该能够简单地遍历gzip的读者喜欢你用常规的流(according to the docs

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
gz.each_line do |line| 
    puts line 
end 
+0

这会在阅读完成后自动关闭文件吗? – Rohit 2015-08-14 20:49:10

+3

是,否 - 如果GzipReader直接在文件上运行,您可能需要关闭它。但在这种情况下,我假定'open'方法打开文件,因此您必须关闭'inline' IO流。 – Tigraine 2015-08-24 08:21:00

+2

哇! 4年后,仍然回复对你的回答的评论。 现在,这是奉献! 再次感谢。 – Rohit 2015-08-25 04:47:27

1

试试这个:

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
while output = gz.gets 
    puts output 
end 
+1

使用'while'作品,但@Tigraine的'each_line'在Ruby中更具惯用性。 – 2011-12-30 23:31:28

+2

我知道。我甚至想过删除我的答案,但后来决定离开它,为了完整性。 – 2011-12-30 23:34:27

+2

这是一个很好的理由。我定期展示替代方式来完成某件事。而且,这就是Ruby的美妙之处,我们可以用更接近于其他语言学习的风格编写代码,这有助于我们作为程序员更易于访问和移植。这符合Matz对开发人员透明的目标。 – 2011-12-30 23:41:57

1

其他的答案显示了如何读取文件中的行做而不是如何只捕捉一次错误。建立在@ Tigraine的回答是:

require 'set' 

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 

errors = Set.new 
# or ... 
# errors = [].to_set 

gz.each_line do |line| 
    errors << line if (line[/^Error:/]) 
    # or ... 
    # errors << line if (line['Error:']) 
end 

puts errors 

设置的行为像数组,但使用Hash建成,所以它就像一个哈希但我们只关心键,即唯一的值存储。如果您尝试添加重复项,则它们将被丢弃,仅留下唯一的值。你可以使用一个数组,然后使用uniq,但是一个Set会在你前面管理它。

>> require 'set' 
=> true 
>> errors = Set.new 
=> #<Set: {}> 
>> errors << 'a' 
=> #<Set: {"a"}> 
>> errors << 'b' 
=> #<Set: {"a", "b"}> 
>> errors << 'a' 
=> #<Set: {"a", "b"}>