这并不简单,因为 python 不像其他编程语言那样专为这类东西而设计。
首先:您必须将管道切换为非阻塞。否则,对read() 的调用将在所有情况下阻塞。这是通过以下代码完成的:
fd = p.stdout.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
注意:请注意,p.stdout 不是您到其他进程的输出流,而是该进程的输出流,即您的输入流。
现在我们有了一个非阻塞流,我们可以继续。
第二次:等到数据可用。这可以通过select() 来完成:
streams = [ p.stdout ]
temp0 = []
readable, writable, exceptional = select.select(streams, temp0, temp0, 5)
if len(readable) == 0:
raise Exception("Timeout of 5 seconds reached!")
据我所知,exceptional 永远不会收到任何数据,因为我们在这里处理管道。
第三:现在让我们读取数据:
temp = bytearray(4096)
numberOfBytesReceived = p.stdout.readinto(temp)
if numberOfBytesReceived <= 0:
raise Exception("No data received!")
其他信息:
当然,您不知道发送者实际发送了多少数据。您必须重复读取数据并检查是否有发送过程的所有输出。您可以确定进程是否关闭了流——但这会使这个问题完全过时,因为根本不需要这种 I/O 实现——或者直到某些特定的 all-data -sent-标记已发送。
补充说明:
如果您需要在管道上执行多次读取以完全读取由另一个进程发送的有意义的数据块,您最终将在循环中执行此操作并将数据附加到缓冲区。这需要将您的p.stout.readinto(temp) 已写入的临时缓冲区中的数据复制到您要保存数据的真实缓冲区。据我所知,python 中没有更有效的方法,因为readinto() 总是(!)写入预分配缓冲区的开头。不可能在特定偏移处写入数据,因为这在其他编程语言中是众所周知的。如果在我看来真的没有其他方法,那么这必须被认为是python API中的设计缺陷。