Den*_*din 2 ruby gzip ruby-on-rails bzip
我正在尝试编写一个实用程序函数来打开三种不同类型的文件:.bz2、.gz 和.txt。我不能只是使用File.read,因为它给我压缩文件带来了垃圾。我正在尝试使用,Open3.popen3以便可以给它一个不同的命令,但我收到以下代码的“没有这样的文件或目录”错误:
def file_info(file)
cmd = ''
if file.match("bz2") then
cmd = "bzcat #{file}"# | head -20"
elsif file.match("gz") then
cmd = "gunzip -c #{file}"
else
cmd = "cat #{file}"
end
puts "opening file #{file}"
Open3.popen3("#{cmd}", "r+") { |stdin, stdout, stderr|
puts "stdin #{stdin.inspect}"
stdin.read {|line|
puts "line is #{line}"
if line.match('^#') then
else
break
end
}
}
end
> No such file or directory - cat /tmp/test.txt
Run Code Online (Sandbox Code Playgroud)
该文件确实存在。我尝试使用cmd而不是#{cmd}在popen3 cmd.
我决定将其硬编码为 txt 文件,如下所示:
def file_info(file)
puts "opening file #{file}"
Open3.popen3("cat", file, "r+") { |stdin, stdout, stderr|
puts "stdin #{stdin.inspect}"
stdin.read {|line|
puts "line is #{line}"
if line.match('^#') then
else
break
end
}
}
end
Run Code Online (Sandbox Code Playgroud)
这给了我回馈:
stdin #<IO:fd 6>
not opened for reading
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
当我做:
Open3.popen3("cat",file) { |stdin, stdout, stderr|
puts "stdout is #{stdout.inspect}"
stdout.read {|line|
puts "line is #{line}"
if line.match('^#') then
puts "found line #{line}"
else
break
end
}
}
Run Code Online (Sandbox Code Playgroud)
我没有收到任何错误,并且打印了 STDOUT 行,但是这两个行语句都没有打印出任何内容。
在尝试了几种不同的方法之后,我想出的解决方案是:
cmd = Array.new
if file.match(/\.bz2\z/) then
cmd = [ 'bzcat', file ]
elsif file.match(/\.gz\z/) then
cmd = [ 'gunzip', '-c', file ]
else
cmd = [ 'cat', file ]
end
Open3.popen3(*cmd) do |stdin, stdout, stderr|
puts "stdout is #{stdout}"
stdout.each do |line|
if line.match('^#') then
puts "line is #{line}"
else
break
end
end
end
Run Code Online (Sandbox Code Playgroud)
来自精美的手册(写得相当混乱):
* popen3( cmd, &block)
[...]
因此可以接受命令行字符串和参数字符串列表,如下所示。Run Code Online (Sandbox Code Playgroud)Open3.popen3("echo a") {|i, o, e, t| ... } Open3.popen3("echo", "a") {|i, o, e, t| ... } Open3.popen3(["echo", "argv0"], "a") {|i, o, e, t| ... }
所以当你这样做时:
Open3.popen3("cat /tmp/test.txt", "r+")
Run Code Online (Sandbox Code Playgroud)
popen3认为命令名称是cat /tmp/test.txt并且r+是该命令的参数,因此您看到的特定错误:
没有这样的文件或目录 - cat /tmp/test.txt
不需要通常的模式标志 ( "r+") Open3.popen3,因为它将分隔读取、写入和错误的句柄;而且,正如您所看到的,尝试提供模式字符串只会导致错误和混乱。
第二种情况:
Open3.popen3("cat", file, "r+") { |stdin, stdout, stderr|
stdin.each {|line|
#...
Run Code Online (Sandbox Code Playgroud)
不起作用,因为stdin这是命令的标准输入,而这就是您要写入的内容而不是从中读取的内容,而是您想要的stdout.read。
您应该将命令构建为数组,并且您的match调用应该更严格一些:
if file.match(/\.bz2\z/) then
cmd = [ 'bzcat', file ]
elsif file.match(/\.gz\z/) then
cmd = [ 'gunzip', '-c', file ]
else
cmd = [ 'cat', file ]
end
Run Code Online (Sandbox Code Playgroud)
然后打他们:
Open3.popen3(*cmd) do |stdin, stdout, stderr|
#...
end
Run Code Online (Sandbox Code Playgroud)
这不仅有效,而且可以让您避免使用有趣的文件名。
您还可以通过跳过非压缩情况并使用它来避免无用的使用cat(有人可能会抱怨)。您可能还需要考虑检查文件的字节以查看它包含的内容,而不是依赖扩展名(或使用ruby-filemagic来检查)。Open3.popen3File.open
| 归档时间: |
|
| 查看次数: |
2160 次 |
| 最近记录: |