ruby – IO.popen不工作瘸腿的标准input和标准输出编码

我一直在使用pipe道和IO.popen专门在Ruby中,并遇到了一个问题,我不明白。 我正在尝试将flac进程中的二进制数据写入文件。 我正在使用的代码结构如下。

 # 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过程中input和输出二进制数据,因为我正在尝试创build一个独立于平台( ruby支持受限的当然 )来转码audio文件,并且lame的Windows二进制文件只支持Windows的path名,不是cygwin的。

编辑#1

我在一些地方(我没有保存url,我会尝试在我的浏览器历史logging中IO.popenIO.popen已经知道在Windows中阻塞进程的问题,这可能是这样的。

我曾经玩过其他库,包括Ruby的Open3.popen3Open4 ,然而,在一个非常类似于上面的代码结构的过程中,这个lame过程仍然是挂起,并且没有响应。

编辑#2

我发现这篇文章讨论了Windows的cmd.exe的限制,以及它如何防止使用从文件stream式数据到标准input。

我重构了我的代码,看起来像下面所示,以testing这一点,事实certificate, lame冻结在标准input写。 如果我删除(注释掉)该行,则执行lame过程( 使用“不支持的audio格式”警告 )。 也许这篇文章所说的可以解释我的问题。

 # 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

我发现这个(在第一个答案)提到cygwinpipe道实现是不可靠的stackoverflow 。 这可能实际上可能并不涉及到Windows(至less不是直接),而是cygwin及其仿真。 我已经select使用下面的代码,基于冰冷的答案, 哪个工作

 flac = "flac --decode --stdout \"#{file}\"" lame = "lame -V0 --vbr-new --verbose - \"#{dest}\"" system(flac + ' | ' + lame) 

你试过管子了吗? 字符?
用ruby安装程序在windows上测试过

 require 'open3' command = 'dir /B | sort /R' # a windows example command Open3.popen3(command) {|stdin, stdout, stderr, wait_thr| pid = wait_thr.pid puts stdout.read #<a list of files in cwd in reverse order> } 

其他方法: Ruby管道:我如何将两个子进程的输出连接在一起?

编辑:使用IO::pipe

 require 'open3' command1 = 'dir /B' command2 = 'sort /R' reader,writer = IO.pipe Open3.popen3(command1) {|stdin, stdout, stderr, wait_thr| writer.write stdout.read } writer.close stdout, stderr, status = Open3.capture3(command2, :stdin_data => reader.read) reader.close puts "status: #{status}" #pid and exit code puts "stderr: #{stderr}" #use this to debug command2 errors puts stdout 

嵌入这两者似乎也行得通,但是,正如你所提到的博客所说,必须等待第一个命令完成(而不是实时 – 用ping命令测试)

 stdout2 = '' Open3.popen3(command1) {|stdin, stdout, stderr, wait_thr| stdout2, stderr2, status2 = Open3.capture3(command2, :stdin_data => stdout.read) } puts stdout2