如何逐行读取gzip文件?

13

我有一个gzip文件,现在我是这样读取它的:

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

我认为这将文件转换为字符串,但我想逐行读取它。

我的目的是:文件中有一些带有垃圾信息的警告消息,我想要筛选那些警告消息并将它们写入另一个文件。但是有些警告消息是重复的,所以我必须确保只筛选一次。因此,逐行阅读会对我有所帮助。

3个回答

24

根据文档,您应该能够像处理常规流一样循环使用gzip reader(详见文档

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

这会在读取完成后自动关闭文件吗? - Rohit
3
是和不是 - 如果GzipReader直接操作文件,你可能需要关闭它。但在这种情况下,我假设“open”方法打开文件,因此您必须关闭“inline” IO流。 - Tigraine
2
哇!!已经4年了,仍然回复评论。 那就是专注! 再次感谢。 - Rohit
@Tigraine,出现了list_failed_logins.rb:2: uninitialized constant Zlib (NameError)的错误。 - Nameless
1
@AjayAradhya 你可能需要在你的文件中 require 'zlib' - Tigraine
显示剩余2条评论

1

试一试:

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

1
使用 while 是可以的,但像 @Tigraine 展示的那样,使用 each_line 更符合 Ruby 的惯用方式。 - the Tin Man
2
我知道。我甚至考虑删除我的回答,但最终决定保留它,以便完整。 - Sergio Tulentsev
2
这是一个很好的理由。我会定期展示完成某事的替代方法。而且,Ruby 的美妙之处在于,我们可以使用更接近其他语言学习方式的风格编写代码,这有助于它作为程序员更易于访问和移植。这与 Matz 的目标一致,即使开发者能够透明地使用它。 - the Tin Man

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

Set 的行为类似于 Array,但是它是使用 Hash 构建的,因此它就像一个 Hash,但我们只关心键,即仅存储唯一值。如果您尝试添加重复项,它们将被丢弃,留下唯一值。您可以使用 Array,然后在其上使用 uniq,但 Set 将为您提前管理它。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接