如何在不等待输入的情况下检查可能为空的stdin?

问题描述 投票:3回答:1

我正在尝试从键盘输入中读取内容,而无需等待输入。目的是在True:。

时在“无限”循环ala中使用。

到目前为止,我一直在尝试操作readchar库https://pypi.python.org/pypi/readchar/0.6,但是没有运气。虽然它不等待Enter,但仍然等待一些输入。我不希望它等待输入,而只是检查并返回“”或某个占位符(如果没有输入)。

这是我一直在使用的内容:

def readchar():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

def main():
    while True:
        current = readchar()
        if current == "some letter":
            print("things happen")
python io buffer stdin stdio
1个回答
5
投票

最终构成Python文件对象基础的POSIX I / O函数具有两种不同的模式,即阻塞和非阻塞,由名为O_NONBLOCK的标志控制。特别地,O_NONBLOCK函数说:

[尝试读取文件时……当前没有可用数据...如果设置了read,则read()将返回-1并将errno设置为read

在Python中,此标志在O_NONBLOCK模块中可用。


[EAGAIN]已经打开,所以您不能只将os传递给os函数,所以……您该怎么办?好吧,您实际上might而是想打开sys.stdin。这取决于您的实际操作。在这种情况下,答案是显而易见的。但是,让我们假设您没有。因此,您想更改已经打开的文件的标志。这正是O_NONBLOCK的目的。您可以使用os.open操作读取当前标志,或在/dev/tty的位中读取结果,并在fcntl中读取结果。当然,如果您想还原内容,则可以记住当前标记,以便以后使用。

在Python中,fcntl函数和操作常量在F_GETFL模块中可用。


最后一个问题:O_NONBLOCK不是原始文件对象,它是一个F_SETFL,它在fcntl之上进行Unicode解码,而fcntl本身在fcntl之上添加了缓冲。因此,sys.stdin不是直接调用POSIX TextIOWrapper函数。为此,您需要使用TextIOWrapper。如果您想在原始输入和正常输入之间来回切换,则可能还需要进行很多仔细的冲洗。 (请注意,这意味着您放弃了Unicode,而是获得了一个单字节BufferedReader对象,该对象可能是UTF-8字符的一半或终端转义字符的四分之一。希望您期待那。)


现在,当没有可用空间时,BufferedReader返回什么?好吧,这是FileIO的实现,FileIO说:

如果返回0个字节,并且大小不为0,则表明文件结尾。如果对象处于非阻塞模式并且没有字节可用,则返回sys.stdin.read()

换句话说,如果没有可用的内容,您将获得read,对于EOF,将获得sys.stdin.buffer.raw,对于其他任何内容,将获得单字节bytes


所以,把它们放在一起:

FileIO.read

最后一件事:是否有一种方法可以在不读取输入的情况下判断输入是否准备就绪?是的,但不可移植。根据您的平台,RawIOBaseRawIOBase.readRawIOBase.read和/或None可能可用,并且可以在常规文件上使用。可以保证None返回b''而不是bytes。等等。您可以阅读本地手册页。但是,更简单的解决方案是C的stdio所做的事情:添加一个最大1字节的缓冲区,并使用它来实现自己的old_settings = termios.tcgetattr(fd) old_flags = fcntl.fcntl(fd, fcntl.F_GETFL) try: tty.setraw(fd) fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK) return sys.stdin.buffer.raw.read(1) finally: fcntl.fcntl(fd, fcntl.F_SETFL, old_flags) termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) selectpollepoll包装器。

© www.soinside.com 2019 - 2024. All rights reserved.