将40字节的二进制数据读取为ASCII文本

3 投票
3 回答
3899 浏览
提问于 2025-04-16 02:56

我有一些二进制数据,在十六进制编辑器中看起来像这样:
s.o.m.e.d.a.t.a

每个字母之间都有这些点

当我用filehandle.read(40)读取时,它显示了这些点

我知道这些点本来不应该出现,有没有办法用struct解包一些长度为40字节的ascii数据呢?

我试过用'40s'和's',但是显示的数据很奇怪,或者只解包了一个字符,而不是40个。

3 个回答

0

在Python中读取二进制数据时,我使用的是:

val = f.read(1)
val = struct.unpack( 'c' , val )

然后我就可以逐字节地读取我需要的数据。对于一个40字节的结构,我会这样做:

val = f.read(40)
val = struct.unpack( '40c' , val )
1

一个简单粗暴的解决办法是用 s[::2],这里的 s 是你想要处理的80个字符的字节串,这个方法只会考虑每隔一个字节的内容。根据 @fadden 的评论,比较“干净”的解决方案是把数据读成 UTF-16 格式(然后再用 .encode 转换成 ASCII 等等),不过如果简单粗暴的方法能满足你的需求,那可能会更简单、更快(如果原始数据中有一些字符不在最低的256个范围内,简单粗暴的方法可能会得到奇怪的结果,而正确的方法会抛出异常——哪种处理方式更好就要看你的应用需求了...)。

4

如果你的第一个字节是一个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")还是其他什么。

撰写回答