对Python中的字节感到困惑

1 投票
2 回答
8494 浏览
提问于 2025-04-17 12:50

我最近开始用Python解析二进制数据,但对Python处理“字节”的方式感到困惑。举个例子,看看下面的解释器对话:

>>> f = open('somefile.gz', 'rb')
>>> f
<open file 'textfile.gz', mode 'rb' at 0xb77f4d88>
>>> bytes = f.read()
>>> bytes[0]
'\x1f'
>>> len(bytes[0])
1
>>> int(bytes[0])  <---- calling __str__ automatically on bytes[0] ?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '\x1f'

上面的对话显示,bytes[0]的大小是1个字节,但它的__str__表示是十六进制的。没关系,但当我试图把bytes[0]当作一个单独的字节来处理时,结果却很奇怪。

如果我想根据某个规范来解析/理解一个二进制流,而这个规范包括十六进制、二进制和十进制的表示,我该怎么做呢?

举个例子,“前两个字节是\xbeef,接下来是一个十进制的8,然后是一个打包的位域,其中字节的每8位代表一个标志?”我想应该有一些模块可以让这个任务变得简单,但我想从头开始做。

我看到有人提到过struct模块,但有没有办法直接检查读取的字节,而不引入新的模块呢?比如说bytes[0] == 0xbeef

有人能帮我一下,通常人们是怎么用Python解析符合规范的二进制数据的?谢谢。

2 个回答

2

如果你想解析二进制数据,可以看看 struct 模块。这里有一个文档中的例子:

>>> from struct import *
>>> pack('hhl', 1, 2, 3)
'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

想了解更多关于 unpack 的内容哦 :)

所以,如果你想把前两个字节当作一个无符号短整型来读取,并用 0xbeef 来做测试:

struct.unpack('H', bytes[0:2]) == 0xbeef
5

你正在使用Python 2.x。在Python 3.0之前,读取文件(即使是二进制文件)时,返回的其实是一个字符串。你所说的“字节”对象实际上就是一个字符串。像“bytes[0]”这样索引字符串时,返回的只是一个包含1个字符的字符串。

如果你想做的事情,使用struct模块可能是最合适的,但如果你真的想不使用它,也可以这样做:

“像这样:bytes[0] == 0xbeef?”

这样是行不通的,因为0xbeef是一个两字节的序列,而bytes[0]只有一个字节。你可以这样做:

bytes[0:2] == b'\xbe\xef'

在Python 3.x中,事情的运作方式更符合你的预期。读取一个二进制文件会返回一个bytes对象,它表现得像是一系列1字节的无符号整数,而不是字符串。

撰写回答