Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 等待外部程序完成对文件的写入_Python_Subprocess_Sox - Fatal编程技术网

Python 等待外部程序完成对文件的写入

Python 等待外部程序完成对文件的写入,python,subprocess,sox,Python,Subprocess,Sox,我有一个Python脚本,精确地说,它调用了一个外部程序sox。现在我必须用sox做几件事,但总是要等到一个文件写完后,才能在下一个命令中将其用作输入文件 SUBSPROCESS.wait不起作用,因为sox的执行将完成,但文件不会写入 以下是我的代码: import tempfile import shlex file_url = '/some/file.wav' out_file = 'some/out.wav' tmp_file = tempfile.NamedTemporaryFile

我有一个Python脚本,精确地说,它调用了一个外部程序sox。现在我必须用sox做几件事,但总是要等到一个文件写完后,才能在下一个命令中将其用作输入文件

SUBSPROCESS.wait不起作用,因为sox的执行将完成,但文件不会写入

以下是我的代码:

import tempfile
import shlex

file_url = '/some/file.wav'
out_file = 'some/out.wav'
tmp_file = tempfile.NamedTemporaryFile()
pad_cmd = 'sox ' + file_url + ' ' + tmp_file.name + ' pad 0.0 3.0'
subprocess.call(shlex.split(pad_cmd))
trim_cmd = 'sox ' + tmp_file.name + ' -t wav ' + out_file + ' trim 0.0 3.0'

等待文件完成写入tmp_file.name的任何方式,而不使用等待固定时间的计时器。或者sox中是否有一种内置的方式将输出文件用作输入?特殊文件名-不适用于pad和trim。

您可以等待该文件,然后才能读取:

handle = open(tmp_file.name)
from subprocess import select
select.select([handle], [], [])
如果:

然后您可以用Python编写它:

#!/usr/bin/env python
from subprocess import Popen, PIPE

pad = Popen(["sox", "input.wav", "-t", "wav", "-", "pad", "0.0", "3.0"],
            stdout=PIPE)
trim = Popen(['sox', '-t', 'wav', '-', 'out.wav', 'trim', '0.0', '3.0'],
             stdin=pad.stdout)
pad.stdout.close() # notify pad on write if trim dies prematurely
pipestatus = [p.wait() for p in [pad, trim]]
#!/usr/bin/env python
from subprocess import Popen, check_call

with named_pipe() as path:
    trim = Popen(["sox", path, '-t', 'wav', 'out.wav', 'trim', '0.0', '3.0'])
    check_call(["sox", "input.wav", path, "pad", "0.0", "3.0"]) # pad
rc = trim.wait()
注意:如果不使用不受信任的输入来构造命令,则可以将其作为单行传递,以提高可读性。在这种情况下,shell将创建管道:

#!/usr/bin/env python
from subprocess import check_call

cmd = "sox input.wav - -t wav pad 0.0 3.0 | sox - -t wav out.wav trim 0.0 3.0"
check_call(cmd, shell=True)
如果无法写入/读取stdout/stdin,则可以尝试命名管道,以避免等待文件:

#!/bin/sh
mkfifo /tmp/sox.fifo
sox /tmp/sox.fifo -t wav out.wav trim 0.0 3.0 & # read from fifo
sox input.wav /tmp/sox.fifo pad 0.0 3.0         # write to fifo
或者在Python中也是如此:

#!/usr/bin/env python
from subprocess import Popen, PIPE

pad = Popen(["sox", "input.wav", "-t", "wav", "-", "pad", "0.0", "3.0"],
            stdout=PIPE)
trim = Popen(['sox', '-t', 'wav', '-', 'out.wav', 'trim', '0.0', '3.0'],
             stdin=pad.stdout)
pad.stdout.close() # notify pad on write if trim dies prematurely
pipestatus = [p.wait() for p in [pad, trim]]
#!/usr/bin/env python
from subprocess import Popen, check_call

with named_pipe() as path:
    trim = Popen(["sox", path, '-t', 'wav', 'out.wav', 'trim', '0.0', '3.0'])
    check_call(["sox", "input.wav", path, "pad", "0.0", "3.0"]) # pad
rc = trim.wait()
其中,命名管道定义为:

import os
from contextlib import contextmanager
from shutil     import rmtree
from tempfile   import mkdtemp

@contextmanager
def named_pipe():
    dirname = mkdtemp()
    try:
        path = os.path.join(dirname, 'named_pipe')
        os.mkfifo(path)
        yield path
    finally:
        rmtree(dirname)

你能详细说明一下吗?我不确定如何知道文件何时可以读取?select.selec[handle],[]是否返回某些内容?不要从子流程模块导入select,而是使用导入select。如果f=openfilename成功,则select.select[f],[]可能会立即返回,即您不能使用它来等待文件。将执行sox,但不会完成文件写入。-如果这是真的,那么可能是sox只是另一个程序的启动程序,该程序对文件进行实际写入,例如,如果文件是在现有文本编辑器的选项卡中打开的,那么在这种情况下:对于任意子流程,您所要求的无法完成,但您可能会破解某些特定于sox的解决方案。你绝对确定sox退出时文件还没有完成吗?你能指示sox写入标准输出而不是文件吗?例如,sox input.wav-pad 0.0 3.0 | sox--t wav out.wav trim 0.0 3.0?@J.F.Sebastian噢,不知道特殊的文件名。不幸的是,它似乎不起作用。我得到sox失败格式:无法确定两次的-'`错误类型。@J.F.Sebastian我不能绝对确定,在sox退出时文件是否完成。我的一些测试表明了这一点。但我刚刚发现给标准输出写东西确实管用。您只需在两个命令中指定文件类型。虽然sox在为wav文件创建头文件时遇到了一些问题,但在我的例子中这不是问题。命令应为sox input.wav--t wav pad 0.0 3.0 | sox--t wav out.wav trim 0.0 3.0Oh。上面的命令有点错误。它应该是:sox input.wav-t wav-pad 0.03.0 | sox-t wav-out.wav trim 0.03.0