将40字节的二进制数据读取为ASCII文本
我有一些二进制数据,在十六进制编辑器中看起来像这样:
s.o.m.e.d.a.t.a
每个字母之间都有这些点
当我用filehandle.read(40)读取时,它显示了这些点
我知道这些点本来不应该出现,有没有办法用struct解包一些长度为40字节的ascii数据呢?
我试过用'40s'和's',但是显示的数据很奇怪,或者只解包了一个字符,而不是40个。
3 个回答
在Python中读取二进制数据时,我使用的是:
val = f.read(1)
val = struct.unpack( 'c' , val )
然后我就可以逐字节地读取我需要的数据。对于一个40字节的结构,我会这样做:
val = f.read(40)
val = struct.unpack( '40c' , val )
一个简单粗暴的解决办法是用 s[::2]
,这里的 s
是你想要处理的80个字符的字节串,这个方法只会考虑每隔一个字节的内容。根据 @fadden 的评论,比较“干净”的解决方案是把数据读成 UTF-16
格式(然后再用 .encode
转换成 ASCII 等等),不过如果简单粗暴的方法能满足你的需求,那可能会更简单、更快(如果原始数据中有一些字符不在最低的256个范围内,简单粗暴的方法可能会得到奇怪的结果,而正确的方法会抛出异常——哪种处理方式更好就要看你的应用需求了...)。
如果你的第一个字节是一个ASCII字符(就像你例子里显示的那样),而第二个字节是'\x00',那么你很可能是在处理UTF-16LE编码的数据。
不过,最好能明确地告诉我们你文件开头的几个字节到底是什么。请按照下面的步骤操作:
python -c "print(repr(open('myfile.txt', 'rb').read(20)))"
然后把结果编辑到你的问题里。如果有任何机密信息,请在编辑时保留其大意。
我们特别想看看文件是否以UTF-16的字节顺序标记(BOM)开头,像是'\xff\xfe'
或者'\xfe\xff'
。
另外,你使用的是哪个平台(Windows还是Linux)?这个文件是怎么生成的?
更新 我对你说的这句话有点困惑:“我试过'40s'和's',但显示出奇怪的数据,或者只解包了1个字符而不是40个。”请看看以下例子:
>>> data = "q\x00w\x00"
>>> unpack("4s", data)
('q\x00w\x00',) # weird? it's effectively tuple([data])
>>> unpack("s", data)
# doesn't produce a string of length 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: unpack requires a string argument of length 1
>>> unpack("ssss", data)
('q', '\x00', 'w', '\x00') # this == tuple(data)
>>>
@pxh评论道:“你只得到一个字符是因为那些点被当作ASCII NUL(空字符)读取了,所以字符串在这里就结束了。”我很怀疑@pxh是否能证明struct.unpack使用"s"
格式在任何方面都依赖于数据中的单个字节值,无论是"\x00"
)还是其他什么。