【问题标题】:How to read stdin buffer in advance before an EOF in python3?如何在python3中的EOF之前提前读取stdin缓冲区?
【发布时间】:2018-11-01 13:41:53
【问题描述】:

在我的python代码中,我编写了以下函数来接收来自标准输入的自定义二进制包。

def recvPkg():
     ## The first 4 bytes stands for the remaining package length
    Len = int.from_bytes(sys.stdin.buffer.read(4), byteorder='big', signed=True)
     ## Then read the remaining package
    data = json.loads(str(sys.stdin.buffer.read(Len), 'utf-8'))
     ## do something...

while True:
    recvPkg()

然后,在另一个 Node.js 程序中,我将该 python 程序作为子进程生成,并向其发送字节。

childProcess = require('child_process').spawn('./python_code.py');
childProcess.stdin.write(someBinaryPackage)

我希望子进程在收到包后从其标准输入缓冲区中读取并给出输出。但它不起作用,我认为原因是子进程不会开始读取,除非它的标准输入缓冲区接收到一个信号,比如 EOF。作为证明,如果我在 stdin.write 之后关闭 childProcess 的 stdin,python 代码将工作并立即接收所有缓冲包。这不是我想要的方式,因为我需要打开 childProcess 的标准输入。那么node.js有没有其他方法可以向childProcess发送信号以通知从stdin缓冲区读取?

(抱歉英语不好。

【问题讨论】:

  • 你确定Len 是正确的吗? sys.stdin.buffer.read(Len) 将从标准输入读取字节,直到它收到 Len 字节。在那之前,这将是一个阻塞调用。所以.read(5) 如果你发送它“abcd”将不会做任何事情,但是当你发送最后一个“e”时它会继续。如果Len 包含确定消息长度的字节,则需要将数据加载更改为.read(Len-4)
  • @alxwrd 感谢您的评论。我确信 python sys.stdin.buffer.read() 在某些刷新事件发生之前不会读取任何内容。确实,.read(5) 在仅收到“abcd”时不会读取,但这不是我的情况。我向 childProcess 发送长字节,如果我在 write() 之后添加“childProcess.stdin.end()”,则读取 python 代码。否则,它不会。我还尝试重定向来自文件的输入,并且它可以工作,因为我认为来自文件的流最终会有一个 EOF。

标签: python node.js stdin


【解决方案1】:

来自维基百科(强调我的):

来自终端的输入永远不会真正“结束”(除非设备已断开连接),但在终端中输入多个“文件”很有用,因此键序列 保留以指示输入结束。在 UNIX 中,击键到 EOF 的转换由 终端驱动程序 执行,因此程序不需要将终端与其他输入文件区分开来。

无法按照您的预期发送EOF 字符。 EOF 并不是真正存在的角色。当您在终端中时,您可以在 Windows 上按顺序键 ctrlz,然后按 ctrld在类 UNIX 环境中。这些为终端生成控制字符(Windows 上的代码 26,UNIX 上的代码 04)并由终端读取。终端(在阅读此代码后)将基本上停止写入程序 stdin关闭它。

在 Python 中,文件对象将永远.read()。 EOF 条件是.read() 返回''。在其他一些语言中,这可能是-1,或其他一些条件。

考虑:

>>> my_file = open("file.txt", "r")
>>> my_file.read()
'This is a test file'
>>> my_file.read()
''

这里的最后一个字符不是EOF,那里什么都没有。 Python 有.read() 直到文件末尾,不能再有.read()

因为stdin 在特殊类型的“文件”中没有结尾。 必须定义那个目的。终端已将该端定义为控制字符,但在这里您不是通过终端将数据传递给stdin,您必须自己管理它。

只是关闭文件

输入 [...] 永远不会真正“结束”(除非设备断开连接)

关闭stdin 可能是这里最简单的解决方案。 stdin 是一个无限文件,所以一旦你写完它,就关闭它。

期待你自己的控制角色

另一种选择是定义您自己的控制字符。你可以在这里使用任何你想要的东西。下面的示例使用 NULL 字节。

Python
class FileWithEOF:
    def __init__(self, file_obj):
        self.file = file_obj
        self.value = bytes()
    def __enter__(self):
        return self
    def __exit__(self, *args, **kwargs):
        pass
    def read(self):
        while True:
            val = self.file.buffer.read(1)
            if val == b"\x00":
                break
            self.value += val
        return self.value

data = FileWithEOF(sys.stdin).read()
节点
childProcess = require('child_process').spawn('./python_code.py');
childProcess.stdin.write("Some text I want to send.");
childProcess.stdin.write(Buffer.from([00]));

你可能读错了长度

我认为您在 Len 中捕获的值小于文件的长度。

Python
import sys

while True:
    length = int(sys.stdin.read(2))
    with open("test.txt", "a") as f:
        f.write(sys.stdin.read(length))
节点
childProcess = require('child_process').spawn('./test.py');

// Python reads the first 2 characters (`.read(2)`)
childProcess.stdin.write("10"); 

// Python reads 9 characters, but does nothing because it's
// expecting 10. `stdin` is still capable of producing bytes from
// Pythons point of view.
childProcess.stdin.write("123456789");

// Writing the final byte hits 10 characters, and the contents
// are written to `test.txt`.
childProcess.stdin.write("A");

【讨论】:

  • 非常感谢。我已经测试了 FileWithEOF 并且它运行良好。Thongh 它没有解决我的问题,我想知道我的 NodeJs 代码是否出了问题,也许是回调机制中出现了问题。无论如何,对于这个问题,您已经给出了足够的解决方案和解释。谢谢:)
猜你喜欢
  • 1970-01-01
  • 2011-05-10
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多