我想从stdin读取二进制PNM图像文件。该文件包含一个编码为ASCII文本的标题和一个二进制的有效负载。作为阅读标题的简化示例,我创建了以下代码段:
#! /usr/bin/env python3
import sys
header = sys.stdin.readline()
print("header=["+header.strip()+"]")
我将它作为“test.py”(来自Bash shell)运行,在这种情况下它可以正常工作:
$ printf "P5 1 1 255\n\x41" |./test.py
header=[P5 1 1 255]
但是,二进制有效负载的微小变化会破坏它:
$ printf "P5 1 1 255\n\x81" |./test.py
Traceback (most recent call last):
File "./test.py", line 3, in <module>
header = sys.stdin.readline()
File "/usr/lib/python3.4/codecs.py", line 313, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 11: invalid start byte
有没有一种简单的方法可以在Python 3中使用它?
答案 0 :(得分:2)
要读取二进制数据,您应该使用二进制流,例如,使用TextIOBase.detach()
method:
#!/usr/bin/env python3
import sys
sys.stdin = sys.stdin.detach() # convert to binary stream
header = sys.stdin.readline().decode('ascii') # b'\n'-terminated
print(header, end='')
print(repr(sys.stdin.read()))
答案 1 :(得分:1)
从the docs开始,可以使用bytes
从标准输入读取二进制数据(类型sys.stdin.buffer.read()
):
要从/向标准流写入或读取二进制数据,请使用 底层二进制缓冲对象。例如,要写入字节 stdout,使用sys.stdout.buffer.write(b'abc')。
所以这是你可以采取的一个方向 - 以二进制模式读取数据。 readline()
和其他各种功能仍然有效。捕获ASCII字符串后,可以使用decode('ASCII')
将其转换为文本,以进行其他特定于文本的处理。
或者,您可以使用io.TextIOWrapper()
指示在输入流上使用latin-1
字符集。有了这个,隐式解码操作基本上是一个传递操作 - 所以数据将是str
类型(代表文本),但数据用来自的一对一映射表示二进制(尽管每个输入字节可能使用多个存储字节)。
这里的代码适用于任何一种模式:
#! /usr/bin/python3
import sys, io
BINARY=True ## either way works
if BINARY: istream = sys.stdin.buffer
else: istream = io.TextIOWrapper(sys.stdin.buffer,encoding='latin-1')
header = istream.readline()
if BINARY: header = header.decode('ASCII')
print("header=["+header.strip()+"]")
payload = istream.read()
print("len="+str(len(payload)))
for i in payload: print( i if BINARY else ord(i) )
使用以下Bash命令测试每个可能的1像素有效负载:
for i in $(seq 0 255) ; do printf "P5 1 1 255\n\x$(printf %02x $i)" |./test.py ; done