3

当我尝试将 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
4

3 回答 3

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
于 2013-11-04T14:04:19.280 回答
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 初始化魔法,否则请使用它。
  • 超出这一点的所有内容都非常适合 DRYing(不要重复自己)。
  • 您的变量名称在很大程度上没有描述性;使用有用的名称。
  • 不要分配给一个变量并使用它一次,除非它是一个令人讨厌的分配,它会使以后的代码复杂化或导致混乱的代码。
  • list多次以多种方式使用。这是一个糟糕的主意,尤其是当您从非平凡的应用程序转移到大型应用程序时。不要创建“slush”变量,创建有用的命名变量。而且,特别是,当你按照逻辑进行工作时,不要踩到它们。
于 2013-10-25T20:13:15.600 回答
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
于 2013-10-25T15:32:22.723 回答