处理后将外部程序的输出传回给它

时间:2016-10-24 00:54:28

标签: python subprocess

我有一个Fortran代码,它将文件作为输入并将输出写入stdout。为了避免读/写周期,我想在python中运行代码并将输出转换为numpy数组。我可以使用以下函数执行此操作:

def run_fortran(infile):

    import subprocess
    import numpy as np

    cmd = ['./output.e', infile]
    p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
    out, err = p.communicate()

    if p.returncode == 0: 
        return np.array(out.split(),dtype=int)

现在我接受数组,修改它并将其写入文件。新文件再次传递到run_fortran(infile)。我可以避免这一步并以某种方式使用run_fortran的输出而不是传递文件名吗?

我尝试了两个案例但没有成功:

(1)转换为字符串

arr = run_fortran('input.txt')
new_arr = str(arr).replace("[","").replace("]","")
run_fortran(new_arr)

这将返回一个空数组。

(2)使用StringIO转换为文件类型对象

from cStringIO import StringIO
run_fortran(StringIO(new_arr))

这会返回错误:TypeError: execv() arg 2 must contain only strings这是有道理的。

2 个答案:

答案 0 :(得分:0)

在fortran中,read(*,*)read(5,*)read*,语句将从标准输入中读取,如果格式正确,则可以使用。如果您正在处理formatted数据,即任何人类可读的数据,而不是二进制文件,那么您可能需要一个读取循环,如:

do line=1,numlines
  read(*,*) array(line,:)
enddo

不需要openclose条款。因此,如果直接传递您写入文件的内容,则应该能够删除这些语句并将文件unit更改为5*

现在有更有效的方式来进行这种通信,但任何解决方案都是一个很好的解决方案,如果它适合您的目的。

答案 1 :(得分:0)

如果您的Fortran程序('./output.e' AFAICS)可以从stdin读取,不仅可以从常规文件中读取,而且可以通过传递stdin=subprocess.PIPE {{{}来执行临时文件。 3}} “现有文件描述符(正整数)[或]现有文件对象”)。在UNIX中,总是/dev/stdin放在命令行btw上,在Windows中,有con

但是,如果程序由于处理的性质而无法在“会话”中工作(即不能连续运行并且在可用时提供新数据),则必须重复调用它。

请注意,您必须处理不同线程中的不同管道以避免死锁。因此,要么使用other valid values are(但是程序无法连续运行),要么手动生成stdout / stderr个帖子(communicate()执行的操作;而不是stdin因为输出读取代码必须在开始写入stdin时运行,否则外部程序可能会在写入时“设备上没有剩余空间”时阻塞。

以下是连续运行程序的示例代码:

p=subprocess.Popen(argv,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
while True:
    #the only more elegant way to return a value from a thread is with a Thread subclass,
    # see http://stackoverflow.com/questions/6893968/how-to-get-the-return-value-from-a-thread-in-python
    output_container=[]
    ot=threading.Thread(target=_outputreaderthread,args=(p.stdout,output_container,data))
    ot.start()
    p.stdin.write(data)
    ot.join()
    output=output_container[0]

    data=process_output(output)
    if no_more_processing_needed(data): break
p.stdin.close()
if p.wait()!=0:raise subprocess.CalledProcessError(p.returncode,argv)

def _outputreaderthread(stream,container,data):
    #since there's no process termination as an end mark here,
    # you need to read exactly the right number of bytes to avoid getting blocked.
    #use whatever technique is appropriate for your data (e.g. readline()'s)
    output=stream.read(calculate_output_size(data))
    container.append(output)