3.5 字节到大整数的打包与解包¶

问题¶

你有一个字节字符串并想将它解压�一个整数。或者,你需�将一个大整数转�为一个字节字符串。

解决方案¶

�设你的程�需�处�一个拥有128�长的16个元素的字节字符串。比如:

data = b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'

为了将bytes解�为整数,使用 int.from_bytes() 方法,并�下�这样指定字节顺�:

>>> len(data)
16
>>> int.from_bytes(data, 'little')
69120565665751139577663547927094891008
>>> int.from_bytes(data, 'big')
94522842520747284487117727783387188
>>>

为了将一个大整数转�为一个字节字符串,使用 int.to_bytes() 方法,并�下�这样指定字节数和字节顺�:

>>> x = 94522842520747284487117727783387188
>>> x.to_bytes(16, 'big')
b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
>>> x.to_bytes(16, 'little')
b'4\x00#\x00\x01\xef\xcd\x00\xab\x90x\x00V4\x12\x00'
>>>

讨论¶

大整数和字节字符串之间的转��作并�常�。 然而,在一些应用领域有时候也会出现,比如密�学或者网络。 例如,IPv6网络地�使用一个128�的整数表示。 如果你�从一个数�记录中��这样的值的时候,你就会�对这样的问题。

作为一�替代方案,你�能想使用6.11�节中所介�的 struct 模��解压字节。 这样也行得通,�过利用 struct 模��解压对于整数的大�是有�制的。 因此,你�能想解压多个字节串并将结果�并为最终的结果,就�下�这样:

>>> data
b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
>>> import struct
>>> hi, lo = struct.unpack('>QQ', data)
>>> (hi << 64) + lo
94522842520747284487117727783387188
>>>

字节顺�规则(little或big)仅仅指定了构建整数时的字节的低�高�排列方�。 我们从下�精心构造的16进制数的表示中�以很容易的看出�:

>>> x = 0x01020304
>>> x.to_bytes(4, 'big')
b'\x01\x02\x03\x04'
>>> x.to_bytes(4, 'little')
b'\x04\x03\x02\x01'
>>>

如果你试�将一个整数打包为字节字符串,那么它就��适了,你会得到一个错误。 如果需�的�,你�以使用 int.bit_length() 方法�决定需�多少字节��存储这个值。

>>> x = 523 ** 23
>>> x
335381300113661875107536852714019056160355655333978849017944067
>>> x.to_bytes(16, 'little')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too big to convert
>>> x.bit_length()
208
>>> nbytes, rem = divmod(x.bit_length(), 8)
>>> if rem:
... nbytes += 1
...
>>>
>>> x.to_bytes(nbytes, 'little')
b'\x03X\xf1\x82iT\x96\xac\xc7c\x16\xf3\xb9\xcf...\xd0'
>>>