Python通过subprocess与无GUI软件交互报错:写入已关闭文件
Python与Multiwfn_noGUI交互报错:ValueError: write to closed file
问题描述
尝试用Python调用无GUI版Multiwfn_noGUI,流程为启动进程后等待响应,再输入特定命令,但代码运行报错,进程提前终止。
原代码
process = subprocess.Popen(f"Multiwfn_noGUI 178_aromat.fchk", shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) output, _ = process.communicate() if "based on wavefunction" in str(output): string_val = "y" input_bytes = string_val.encode('utf-8') process.stdin.write(input_bytes) process.stdin.flush() output, _ = process.communicate() if "300 Other functions (Part 3)" in output: string_val = "25" input_bytes = string_val.encode('utf-8') process.stdin.write(input_bytes) process.stdin.flush()
报错信息
Traceback (most recent call last): File "homa_calc.py", line 285, in <module> process.stdin.write(input_bytes) ValueError: write to closed file
问题原因
subprocess.communicate()方法执行后会自动关闭进程的stdin、stdout和stderr管道,同时等待进程终止。第一次调用process.communicate()后,process.stdin已被关闭,后续再调用process.stdin.write()必然触发"write to closed file"错误,且此时进程已经终止,后续操作完全无效。
修复方案
方案1:一次性传入所有输入(适合固定流程)
如果Multiwfn_noGUI的交互流程固定,可以把所有需要输入的命令拼接好,通过communicate()一次性传入,无需分步操作:
import subprocess # 拼接所有命令,每个命令后加换行符模拟终端回车 input_commands = "y\n25\n" process = subprocess.Popen( "Multiwfn_noGUI 178_aromat.fchk", shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, text=True # 文本模式,无需手动编码解码 ) # 传入输入并获取最终输出 output, error = process.communicate(input=input_commands) # 处理输出和错误 print("进程输出:") print(output) if error: print("错误信息:") print(error)
方案2:逐行读取输出并动态输入(适合需要判断响应的场景)
如果需要根据进程的不同输出动态决定输入内容,需逐行读取stdout,避免使用communicate():
import subprocess process = subprocess.Popen( "Multiwfn_noGUI 178_aromat.fchk", shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, # 开启行缓冲,确保实时读取输出 universal_newlines=True ) # 逐行读取进程输出 for line in iter(process.stdout.readline, ''): print(f"进程输出:{line.strip()}") if "based on wavefunction" in line: process.stdin.write("y\n") process.stdin.flush() elif "300 Other functions (Part 3)" in line: process.stdin.write("25\n") process.stdin.flush() # 可根据需求添加更多判断逻辑 # 处理剩余输出和错误 remaining_output = process.stdout.read() error_output = process.stderr.read() print(f"剩余输出:{remaining_output}") if error_output: print(f"错误信息:{error_output}") process.wait()
注意事项
- 使用
text=True(Python3.7+)可直接用字符串交互,省去手动编码字节的步骤。 - 逐行读取时必须设置
bufsize=1开启行缓冲,否则进程输出会被缓存,导致无法实时读取。 - 所有输入命令后必须加换行符
\n,模拟终端回车操作,否则Multiwfn_noGUI不会处理输入。
内容的提问来源于stack exchange,提问作者Limmi
相关产品推荐
相关产品推荐

