gpt4 book ai didi

ruby-on-rails - Open3.popen3 函数打开 bz、gz 和 txt 文件时出现 'No such file or directory' 或 'not opened for reading' 错误?

转载 作者:太空宇宙 更新时间:2023-11-03 17:39:14 24 4
gpt4 key购买 nike

我正在尝试编写一个实用函数来打开三种不同类型的文件:.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

文件确实存在。我试过使用 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

这给了我返回:

stdin #<IO:fd 6>
not opened for reading

我做错了什么?

当我这样做时:

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
}
}

我没有收到任何错误,并且打印了 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

最佳答案

来自fine manual (写得相当困惑):

*popen3(cmd, &block)
[...]
So a commandline string and list of argument strings can be accepted as follows.

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+")

popen3 认为命令名称是 cat/tmp/test.txt 并且 r+ 是该命令的参数,因此具体您看到的错误:

No such file or directory - cat /tmp/test.txt

Open3.popen3 不需要通常的模式标志 ("r+"),因为它将分离读取、写入和错误的句柄;而且,如您所见,尝试提供模式字符串只会导致错误和困惑。

第二种情况:

Open3.popen3("cat", file, "r+") { |stdin, stdout, stderr|
stdin.each {|line|
#...

不起作用,因为 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

然后拍打它们:

Open3.popen3(*cmd) do |stdin, stdout, stderr|
#...
end

这不仅有效,而且可以让您远离有趣的文件名。

您还可以通过跳过非压缩情况下的 Open3.popen3 并使用 来避免无用地使用 cat(有人可能会提示) >File.open 代替。您可能还想考虑检查文件的字节以查看它包含的内容,而不是依赖扩展名(或使用 ruby-filemagic 来检查)。

关于ruby-on-rails - Open3.popen3 函数打开 bz、gz 和 txt 文件时出现 'No such file or directory' 或 'not opened for reading' 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8513782/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com