我有一个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
这是有道理的。
答案 0 :(得分:0)
在fortran中,read(*,*)
,read(5,*)
或read*,
语句将从标准输入中读取,如果格式正确,则可以使用。如果您正在处理formatted
数据,即任何人类可读的数据,而不是二进制文件,那么您可能需要一个读取循环,如:
do line=1,numlines
read(*,*) array(line,:)
enddo
不需要open
或close
条款。因此,如果直接传递您写入文件的内容,则应该能够删除这些语句并将文件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)