关于如何从python中的stdin
读取有很多很好的答案,但是我无法找到关于阅读单个字符而不是整行的任何内容。让我解释一下:
我需要读取arduino在串口上发送的信息,然后转发给stdin。处理该信息并将其存储在文本文件中。我在arduino上编写了程序,所以我可以改变信息的发送方式。计划是以开始 - (<
)和结束字符(>
)发送信息,因此它看起来像这样:<height:2342>
还会写出很多不相关的数据,这就是为什么我决定使用上面的表格,所以python脚本可以检测相关信息并捕获它。
我的python脚本会单独检查每个字符的起始字符<
,最好是在输入时,然后捕获信息,直到收到>
。我尝试使用inputchar = sys.stdin.read(1)
获取输入。但是这里的问题是,它永远从stdin
读取,直到捕获换行符(\n
),然后返回输入的第一个字符。
我希望此函数在发送到stdin
后立即返回输入的字符,而不是等待换行符。我怎么做到这一点?
平台:Raspberry Pi Zero W,Raspbian Jessy,Python 2.7
我知道我可以使用 inputline = sys.stdin.readline()
并更改Arduino程序以在信息之后发送换行符。然后分析整行(可能很长)并提取信息。但我觉得这不是一个干净的方法。
串口更新:遗憾的是,我无法直接从python访问串口,因为还有第二个python脚本需要写入串口。由于只有一个可以访问端口,因此解决方案是将串行端口重定向到stdin
和stdout
。请参阅我的问题Access one Serial Port with two Python Scripts
答案 0 :(得分:1)
这是因为您terminal is in cooked mode。你可以用例如tty.setcbreak或curses.cbreak禁用线路缓冲。这是一个Unix的东西,特别是Python特有的。
示例:
import sys, tty
tty.setcbreak(sys.stdin.fileno())
请注意,这会产生其他影响,例如禁用echo,并在程序退出时保持不变。通常,诸如curses上下文管理器之类的更高级别接口用于处理密钥解析(箭头键,例如,发送转义序列)和清理。
Python之外的主要命令行工具是stty。
答案 1 :(得分:0)
sys.stdin.read(1)
是一种正确的方法。
在点击输入之前,sys.stdin
处没有输入。该行缓冲是在您的程序之外执行的,如果您想使用sys.stdin
,则无法对其执行任何操作。
答案 2 :(得分:0)
我无法重现您描述的行为......
在我的Raspbian上执行 - 在RPI2上:
$ cat a.py
#!/usr/bin/env python2
import sys
while True:
print "Got", ord(sys.stdin.read(1))
$ echo -n "Test" | hexdump -C
00000000 54 65 73 74 |Test|
00000004
$ # No newline in the data sent by echo, as shown by hexdump
$ echo -n "Test" | python2 a.py
Got 84
Got 101
Got 115
Got 116
Got
Traceback (most recent call last):
File "a.py", line 5, in <module>
print "Got", ord(sys.stdin.read(1))
TypeError: ord() expected a character, but string of length 0 found
基本上,sys.stdin.read(1)
返回stdin发送的任何字符,而不等待任何换行符。
答案 3 :(得分:0)
另一种方法是将TTY设置为原始模式。我想确定按键的持续时间,并且需要这样做,这样我就不必按Enter键:
#!/usr/bin/env python3
import datetime
import sys
import tty
import termios
# read a single character on a unix system
# https://exceptionshub.com/python-read-a-single-character-from-the-user.html
def read_unix(count: int):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(count)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
while True:
start = datetime.datetime.now()
char = read_unix(1)
end = datetime.datetime.now()
delta = end - start
print(f'char={char}, delta={delta}')