我一直在使用管道,IO.popen
特别是在 Ruby 中,遇到了一个我无法弄清楚的问题。我正在尝试将二进制数据从flac
进程lame
写入到文件中。我正在使用的代码结构如下。
# file paths
file = Pathname.new('example.flac').realpath
dest = Pathname.new('example.mp3')
# execute the process and return the IO object
wav = IO.popen("flac --decode --stdout \"#{file}\"", 'rb')
lame = IO.popen("lame -V0 --vbr-new - -", 'r+b')
# write output from wav to the lame IO object
lame << wav.read
# close pipe for writing (should indicate to the
# process that input for stdin is finished).
lame.close_write
# open up destiniation file and write from lame stdout
dest.open('wb'){|out|
out << lame.read
}
# close all pipes
wav.close
lame.close
但是,它不起作用。运行后flac
,脚本挂起并lame
保持空闲(根本不使用处理器)。不会发生错误或异常。
我在 Windows 7 上使用 cygwin,带有 cygwin ruby 包(1.9.3p429 (2013-05-15) [i386-cygwin])。
我一定做错了什么,非常感谢任何帮助。谢谢!
额外 #1
我想从lame
进程中输入和输出二进制数据,因为我正在尝试创建一个独立于平台(当然是 ruby 支持有限)来转码音频文件,并且 Windows 二进制文件lame
仅支持 Windows 的路径名,而不支持 cygwin 的.
编辑#1
我在某些地方(我没有保存 URL,我会尝试在我的浏览器历史记录中查找它们)阅读了IO.popen
已知 Windows 中阻塞进程的问题,并且可能是这种情况。
我玩过其他库,包括 RubyOpen3.popen3
和Open4
,但是遵循与上述非常相似的代码结构,该lame
过程仍然挂起并且没有响应。
编辑#2
我发现这篇文章谈到了 Windows 的局限性cmd.exe
以及它如何防止使用从文件到标准输入的流数据。
我重构了我的代码,如下所示来测试它,结果证明,lame
在 stdin 写入时冻结。如果我删除(注释掉)该行,则lame
执行该过程(带有“不支持的音频格式”警告)。也许文章所说的可以在这里解释我的问题。
# file paths
file = Pathname.new('example.flac').realpath
dest = Pathname.new('example.mp3')
# some local variables
read_wav = nil
read_lame = nil
# the flac process, which exits succesfully
IO.popen("flac --decode --stdout \"#{file}\"", 'rb'){|wav|
until wav.eof do
read_wav = wav.read
end
}
# the lame process, which fails
IO.popen("lame -V0 --vbr-new --verbose - -", 'r+b'){|lame|
lame << read_wav # if I comment out this, the process exits, instead of hanging
lame.close_write
until lame.eof do
read_lame << lame.read
end
}
编辑#3
我发现这个stackoverflow(在第一个答案中)提到cygwin
管道实现是不可靠的。这实际上可能与 Windows 无关(至少不直接),而是与 cygwin 及其仿真有关。相反,我选择使用以下代码,基于icy的答案,它有效!
flac = "flac --decode --stdout \"#{file}\""
lame = "lame -V0 --vbr-new --verbose - \"#{dest}\""
system(flac + ' | ' + lame)