Python 读取可执行文件输出的常见问题及解决指南
2024-03-03 10:33:02
在 Python 中读取可执行文件输出的常见问题及其解决方案
作为经验丰富的程序员,我在使用 Python 的 subprocess 模块与可执行文件交互时遇到了无法读取可执行文件输出的问题。这个问题困扰了许多 Python 开发人员,因此我决定编写这篇文章来分享我的解决方法。
问题:无法读取可执行文件输出
在 Python 中使用 subprocess 模块与可执行文件交互时,由于以下原因,可能会遇到无法读取可执行文件输出的问题:
1. 非阻塞 I/O
subprocess.Popen() 使用非阻塞 I/O,这意味着它不会等待可执行文件完成输出后再返回。因此,在尝试读取可执行文件的输出之前,需要检查它是否已完成。
2. 缓冲区溢出
默认情况下,可执行文件的输出缓冲在 subprocess.PIPE 中。如果缓冲区已满,可执行文件将挂起,直到有可用的空间。这可能会导致读取操作挂起。
解决方法
要解决此问题,可以使用以下方法:
1. 使用循环轮询
在循环中使用 process.poll() 方法检查可执行文件是否已完成。只要可执行文件仍在运行,就继续轮询。
while process.poll() is None:
# 检查输出
2. 设置 stdout 缓冲区大小
可以使用 stdout=subprocess.PIPE, bufsize=1 来设置 stdout 缓冲区大小为 1 字节。这将强制可执行文件在每次输出一个字节时刷新缓冲区。
3. 使用 non-blocking=True
在 subprocess.Popen() 中将 non-blocking=True 设置为 True。这将使用非阻塞 I/O,但它还要求你明确调用 process.communicate() 来读取输出。
示例代码
使用循环轮询的示例代码如下:
import subprocess
import re
EXE_PATH = 'C:/path/to/executable.exe'
def get_next_context(process):
match = None
out = ''
while process.poll() is None:
out += process.stdout.read(1)
match = re.match(r'Host IP: (.+)\nHost User: (.+)\nPassword: ', out)
if match is not None:
return match.group(1), match.group(2)
return None, None
if __name__ == '__main__':
p = subprocess.Popen([EXE_PATH], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, shell=True, text=True)
try:
out = ''
while p.poll() is None:
ip, user = get_next_context(p)
if ip is None:
# Process is done and there are no more passwords to accept
break
password = input('Password for host {} and user {}: '.format(ip, user))
p.stdin.write('{}\r\n'.format(password))
if p.poll() is None:
p.stdin.flush()
finally:
p.kill()
注意事项
对于某些可执行文件,即使使用这些方法,也可能无法读取其输出。这是因为可执行文件可能使用了自己的缓冲或 I/O 机制。在这种情况下,需要研究可执行文件的文档或与开发人员联系以获得特定解决方案。
常见问题解答
1. 为什么我无法使用 process.stdout.read() 直接读取可执行文件的输出?
process.stdout.read() 会立即尝试读取可执行文件的输出,即使可执行文件尚未完成输出。这可能会导致阻塞或读取不完整的数据。
2. 我怎样知道可执行文件是否已完成输出?
可以使用 process.poll() 方法检查可执行文件是否已完成。如果 process.poll() 返回 None,表示可执行文件仍在运行。如果返回一个整数,表示可执行文件已完成,并且整数的值是退出代码。
3. 如何设置 stdout 缓冲区大小?
可以使用 subprocess.PIPE, bufsize=1 来设置 stdout 缓冲区大小为 1 字节。这将强制可执行文件在每次输出一个字节时刷新缓冲区。
4. 如何使用 non-blocking=True?
在 subprocess.Popen() 中将 non-blocking=True 设置为 True。这将使用非阻塞 I/O,但它还要求你明确调用 process.communicate() 来读取输出。
5. 对于使用自定义缓冲或 I/O 机制的可执行文件,我该怎么办?
对于这些可执行文件,需要研究其文档或与开发人员联系以获得特定解决方案。