【问题标题】:How to read binary data over a pipe from another process in python?python - 如何通过管道从python中的另一个进程读取二进制数据?
【发布时间】:2018-02-10 20:47:06
【问题描述】:

我使用以下命令启动另一个进程:

p = subprocess.Popen(binFilePath, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=False)

根据文档p.stdout 现在应该有一个二进制数据流,因为universal_newlines 设置为False

如果其他程序现在发送二进制数据,我该如何读取它?尽管等待读取的数据量有限,但对以下命令的调用不会返回:

returnedData = p.stdout.read()

我想要管道中等待的确切数据量(如果有数据可用,否则阻塞直到数据可用)。那我该怎么做呢?

【问题讨论】:

    标签: python-3.x io subprocess


    【解决方案1】:

    这并不简单,因为 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中的设计缺陷。

    【讨论】:

      猜你喜欢
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      相关资源
      最近更新 更多