我正在尝试从键盘输入中读取内容,而无需等待输入。目的是在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文件对象基础的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
最后一件事:是否有一种方法可以在不读取输入的情况下判断输入是否准备就绪?是的,但不可移植。根据您的平台,RawIOBase
,RawIOBase.read
,RawIOBase.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)
和select
或poll
和epoll
包装器。