【问题标题】:ruby - IO.popen not working lame stdin and stdout encodingruby - IO.popen 不工作跛脚的标准输入和标准输出编码
【发布时间】:2013-08-08 13:18:36
【问题描述】:

我一直在使用管道和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 支持当然受限)来对音频文件进行转码,并且lame 的 Windows 二进制文件只支持 Windows 的路径名,不支持 cygwin 的。

编辑#1

我在某些地方读到(我没有保存 URL,我会尝试在浏览器历史记录中查找它们)IO.popen 已知 Windows 中的阻塞进程存在问题,并且可能是这种情况。

我曾尝试过其他库,包括 Ruby 的 Open3.popen3Open4,但是遵循与上述非常相似的代码结构,lame 进程仍然挂起并且没有响应。

编辑#2

我发现this 文章谈到了 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 的回答,which works

flac = "flac --decode --stdout \"#{file}\""
lame = "lame -V0 --vbr-new --verbose - \"#{dest}\""

system(flac + ' | ' + lame)

【问题讨论】:

  • 编辑尝试 Open3#capture3 和设置 :stdin_data 。还是和lame &lt;&lt; read_wav一样?

标签: ruby windows cygwin lame flac


【解决方案1】:

你试过管道| 字符吗?
使用 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 pipes: How do I tie the output of two subprocesses together?

编辑: 使用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

【讨论】:

  • 嗨@icy,感谢您的回答。我已经尝试过并且知道它可以工作,但是对于我的脚本,我打算将解码器/编码器代码分开。这就是为什么我试图通过 ruby​​ 进行管道,而不是在系统级别。
  • 嗨@icy,您是在Windows 的cmd.exe 还是cygwin 下运行脚本?
  • 嗨@icy,你的第一个建议,使用操作系统的管道实现完美,谢谢:)
  • 您的IO::pipe 示例仅在管道缓冲区足够大以捕获第一个命令的整个输出时才有效。否则写入它将阻塞并且第一个命令将永远不会终止,导致第一个 popen3 调用在尝试捕获命令的退出状态时永远挂起。如果您已经在使用open3,为什么不使用pipeline 命令?
  • Open3.capture3:stdin_datapopen3 解决了我的阻塞标准输入。
【解决方案2】:

使用来自Open3pipeline

require "open3"

wavCommand = "flac --decode --stdout \"#{file}\""
lameCommand = "lame -V0 --vbr-new - -"

Open3.pipeline(wavComamnd, lameCommand)

最后一行产生两个进程并将第一个进程的stdout 连接到第二个进程的stdin。或者,您可以使用pipeline_w 访问第一个进程的stdin,或者您可以使用pipeline_r 获得最后一个命令的stdout,或者您可以同时使用pipline_rw

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-07
    • 2021-10-20
    • 2013-09-18
    • 2020-06-11
    • 1970-01-01
    • 2013-06-13
    • 2012-03-16
    • 1970-01-01
    相关资源
    最近更新 更多