如何逐行读取Ruby 1.8.7中的gzip文件?

时间:2013-10-24 22:51:56

标签: ruby gzip zlib

当我尝试逐行读取一个gzip文件到Ruby 1.8.7时,它只读取gzip文件的第一行。这不会发生在我的测试机器上,只发生在我的生产服务器上。

这可能与zlib或Gzipreader有关,但我目前对下一步做什么感到不知所措,任何建议都会很棒。

require 'zlib'
require 'open-uri'

list = Array.new
file = Dir.glob("*").max_by {|f| File.mtime(f)}


File.open(file) do |f|
  gz = Zlib::GzipReader.new(f)
  #something right here is causing an issue on production system
  list = gz.read
  gz.close
end

#I need to take the array and push it to redis
list = list.split("\n")
list.shift
list.each do |list|
    puts list
    puts "\n\n"
end

3 个答案:

答案 0 :(得分:2)

首先,如果脚本的工作目录中有其他文件,您可能希望使用'*.gz'而不是'*'

以下是几个解决方案:

使用GzipReader(推荐)

require 'zlib'

file = Dir.glob('*').max_by { |f| File.mtime(f) }
fd = File.open(file)
gz = Zlib::GzipReader(fd)

gz.readlines[1..-1].each do |line|
  line.chomp!
  puts line, "\n\n"
end

使用IO #popen和zcat

你应该将未经过授权的用户输入传递给Kernel#exec或类似的函数,因为它可以用来执行任意命令。

在您的情况下,您不处理用户输入。因此,需要对脚本的工作目录进行写访问才能执行此操作。但是,这仍然是不好的做法 - 包含特殊shell字符('""$"等)的文件名可能会导致意外问题。

以下解决方案应该与GzipReader解决方案一样安全,但通常使用标准库而不是依赖外部程序是一种好习惯。

file = Dir.glob('*').max_by { |f| File.mtime(f) }

IO.popen(['zcat', file]).readlines[1..-1].each do |line|
  line.chomp!
  puts line, "\n\n"
end

答案 1 :(得分:1)

以下是如何以类似Ruby的方式编写它:

require 'open-uri'

file = Dir.glob("*").max_by { |f| File.mtime(f) }
`zcat #{file}`.split("\n")[1..-1].each do |list|
  puts list, "\n\n"
end

以下是它的作用:

  • 使用反引号打开子shell,使用文件名参数向zcat发送命令。
  • 从输出中捕获的结果输出字符串在行尾分割。
  • 在对数组进行切片以跳过第一个元素之后,使用each循环生成的数组。
  • 每行都以list传递到块中。

原始代码有什么问题?除了以非类似Ruby的方式完成?

  • 不要使用Array.new初始化数组。这不是Java,所以使用[]除非你需要一些较暗的Array初始化魔法。
  • 除此之外的一切都是干燥的目标(不要重复自己)。
  • 您的变量名称在很大程度上是无用的;使用有用的名称。
  • 不要分配给变量并使用它一次,除非它是一个令人讨厌的任务,会使以后的代码混乱或导致混乱。
  • 您多次使用list并以多种方式使用{{1}}。这是一个糟糕的主意,特别是当你从非平凡的应用程序转移到大的应用程序时。不要创建“slush”变量,创建有用的命名变量。特别是,当你按照逻辑运行时,不要踩踏它们。

答案 2 :(得分:0)

我根据以下建议找出了解决方案。 我继续向系统提供zcat +最新文件,将其反馈到一个名为output的字符串中。获取字符串输出并将其放入名为list的数组中,以便每个新行分开。这显然是用于登录目的。 再次感谢。

require 'open-uri'
require 'open3'

list = Array.new

file = Dir.glob("*").max_by {|f| File.mtime(f)}
unzip = "zcat " + file
output = `#{unzip}`
list = output



#I need to take the array and push it to redis
list = list.split("\n")
list.shift
list.each do |list|
    puts list
    puts "\n\n"
end