You are here:  Home » Python » 二进制数据服务模块之struct – 将字节解释为压缩二进制数据(18)Python语言(必读进阶学习教程)(参考资料)

此模块执行Python值和表示为Python bytes对象的C结构之间的转换。这可用于处理存储在文件中的二进制数据或来自网络连接以及其他来源。它使用 Format Strings作为C结构布局的简洁描述以及与Python值的预期转换。

注意

默认情况下,打包给定C结构的结果包括填充字节,以便维护所涉及的C类型的正确对齐; 类似地,在拆包时考虑对齐。选择此行为是为了使压缩结构的字节与相应C结构的内存中的布局完全对应。要处理与平台无关的数据格式或省略隐式填充字节,请使用standard大小和对齐而不是 native大小和对齐:有关详细信息请参阅字节顺序,大小和对齐

几个struct函数(和方法Struct)采用缓冲区 参数。这指的是实现缓冲区协议并提供可读或可读写缓冲区的对象。用于此目的的最常见类型是bytesbytearray,但是可以被视为字节数组的许多其他类型实现缓冲协议,因此可以在不从bytes对象进行额外复制的情况下读取/填充它们。

功能和例外

该模块定义了以下异常和函数:

异常struct.error
在各种场合提出的例外情况; argument是一个描述错误的字符串。
struct.pack格式v1v2… 
返回包含值v1v2,… 的字节对象,根据格式字符串格式打包。参数必须与格式所需的值完全匹配。
struct.pack_into格式缓冲区偏移量v1v2… 
根据格式字符串格式打包值v1v2,… 并将打包字节写入从位置偏移开始的可写缓冲区缓冲区。请注意,offset是必需参数。
struct.unpack格式缓冲区
根据格式字符串格式从缓冲区缓冲区解压缩(可能包含)。结果是一个元组,即使它只包含一个项目。缓冲区的大小(以字节为单位)必须与格式所需的大小相匹配,如下所示。pack(format, ...)calcsize()
struct.unpack_from格式缓冲区偏移= 0 
根据格式字符串格式从位置偏移处开始从缓冲区解包。结果是一个元组,即使它只包含一个项目。缓冲区的大小(以字节为单位,减去偏移量)必须至少为格式所需的大小,如下所示。calcsize()
struct.iter_unpack格式缓冲区
根据格式字符串格式从缓冲区缓冲区迭代解压缩。此函数返回一个迭代器,它将从缓冲区读取大小相同的块,直到其所有内容都被消耗掉。缓冲区的大小(以字节为单位)必须是格式所需大小的倍数,如下所示。calcsize()

每次迭代都会产生格式字符串指定的元组。

版本3.4中的新功能。

struct.calcsize格式
返回与格式字符串格式对应的struct(以及生成的bytes对象)的大小 。pack(format, ...)

格式化字符串

格式字符串是用于在打包和解包数据时指定预期布局的机制。它们由格式字符构成,它指定打包/解包的数据类型。此外,还有用于控制字节顺序,大小和对齐的特殊字符。

字节顺序,大小和对齐

默认情况下,C类型以机器的本机格式和字节顺序表示,并在必要时通过跳过填充字节进行正确对齐(根据C编译器使用的规则)。

或者,根据下表,格式字符串的第一个字符可用于指示打包数据的字节顺序,大小和对齐方式:

字符 字节顺序 尺寸 对准
@ 本地人 本地人 本地人
= 本地人 标准 没有
< 小尾数 标准 没有
> 大端 标准 没有
! 网络(=大端) 标准 没有

如果第一个字符不是其中之一,'@'则假设。

本机字节顺序是big-endian或little-endian,具体取决于主机系统。例如,Intel x86和AMD64(x86-64)是little-endian; 摩托罗拉68000和PowerPC G5都是大端的; ARM和Intel Itanium具有可切换的字节序(双端)。使用sys.byteorder来检查你的系统的字节序。

使用C编译器的sizeof表达式确定本机大小和对齐 。这始终与本机字节顺序相结合。

标准尺寸仅取决于格式字符; 请参阅格式字符部分中的表。

需要注意的区别'@''=':都使用本地字节顺序,但后者的大小和排列是标准化的。

该表格'!'适用于那些声称无法记住网络字节顺序是big-endian还是little-endian的可怜人。

无法指示非本机字节顺序(强制字节交换); 使用适当的选择'<''>'

笔记:

  1. 填充仅在连续的结构成员之间自动添加。在编码结构的开头或结尾没有添加填充。
  2. 使用非原生大小和对齐时不添加填充,例如使用'<‘,’>’,’=’和’!’。
  3. 要将结构的末尾与特定类型的对齐要求对齐,请使用重复计数为零的该类型的代码结束格式。见例子

格式字符

格式字符具有以下含义; 根据类型,C和Python值之间的转换应该是显而易见的。“标准大小”列是指使用标准大小时打包值的大小(以字节为单位); 也就是说,当格式字符串中的一个开始'<''>''!'或 '='。使用本机大小时,打包值的大小取决于平台。

格式 C型 Python类型 标准尺寸 笔记
x 填充字节 没有价值
c char 长度为1的字节 1
b signed char 整数 1 (1),(3)
B unsigned char 整数 1 (3)
? _Bool 布尔 1 (1)
h short 整数 2 (3)
H unsigned short 整数 2 (3)
i int 整数 4 (3)
I unsigned int 整数 4 (3)
l long 整数 4 (3)
L unsigned long 整数 4 (3)
q long long 整数 8 (2),(3)
Q unsigned long long 整数 8 (2),(3)
n ssize_t 整数 (4)
N size_t 整数 (4)
e (7) 浮动 2 (5)
f float 浮动 4 (5)
d double 浮动 8 (5)
s char[] 字节
p char[] 字节
P void * 整数 (6)

版本3.3中已更改:添加了对格式'n''N'格式的支持。

版本3.6中已更改:添加了对'e'格式的支持。

笔记:

  1. '?'转换码对应于_Bool由C99定义的类型。如果此类型不可用,则使用a进行模拟char。在标准模式下,它始终由一个字节表示。

  2. 'q''Q'只有在平台C编译器支持C转换代码在本地模式中可用,或者在Windows上, 。它们始终以标准模式提供。long long__int64

  3. 当尝试使用任何整数转换代码打包非整数时,如果非整数具有__index__()方法,则调用该方法以在打包之前将参数转换为整数。

    在版本3.2中更改:__index__()在非整数中使用该方法是3.2中的新增内容。

  4. 'n''N'转换码只适用于本机的大小(选择为默认或与'@'字节顺序字符)。对于标准大小,您可以使用适合您的应用程序的其他整数格式。

  5. 对于'f''d''e'转换码,填充表示使用IEEE 754 binary32,binary64或binary16格式('f''d''e'分别地),而不管由所述平台中使用的浮点格式的。

  6. 'P'格式字符仅适用于本地字节顺序(选择为默认或与'@'字节顺序字符)。字节顺序字符'='选择使用基于主机系统的小端或大端排序。struct模块不会将其解释为本机排序,因此'P'格式不可用。

  7. IEEE 754二进制16“半精度”类型是在2008年的IEEE 754标准修订版中引入的。它有一个符号位,一个5位指数和11位精度(显式存储10位),并且可以表示大约6.1e-056.5e+04 全精度之间的数字。C编译器并不广泛支持这种类型:在典型的机器上,unsigned short可用于存储,但不能用于数学运算。有关详细信息,请参阅有关半精度浮点格式的Wikipedia页面。

格式字符之前可以是整数重复计数。例如,格式字符串'4h'表示与…完全相同'hhhh'

格式之间的空白字符被忽略; 计数及其格式不得包含空格。

对于's'格式字符,计数被解释为字节的长度,而不是像其他格式字符那样的重复计数; 例如, '10s'表示单个10字节字符串,而'10c'表示10个字符。如果未给出计数,则默认为1.对于打包,字符串将被截断或填充为适当的空字节以使其适合。对于解包,生成的字节对象始终具有指定的字节数。作为一种特殊情况,'0s'表示单个空字符串(同时 '0c'表示0个字符)。

当包装一个值x使用的整数格式(一个'b', 'B''h''H''i''I''l''L', 'q''Q'),如果x是在有效范围之外为该格式然后struct.error上升。

在3.1版中更改:在3.0中,一些整数格式包含超出范围的值而DeprecationWarning不是struct.error

'p'格式字符编码“帕斯卡串”,意思是存储在一个很短的可变长度的字符串的固定数目的字节,由计数给出。存储的第一个字节是字符串的长度,或255,取较小者。字符串的字节如下。如果传入的字符串 pack()太长(长于计数减1),则只count-1存储字符串的前导 字节。如果字符串短于 count-1,则用空字节填充,以便使用所有字节中的精确计数字节。请注意,对于unpack()中,'p'格式字符占用 count的字节,但返回的字符串不能包含超过255个字节。

对于'?'格式字符,返回值为True或 False。打包时,使用参数对象的真值。将打包本机或标准bool表示中的0或1,并且True在解包时将使用任何非零值。

示例

注意

所有示例都假定本机字节顺序,大小和与big-endian机器的对齐。

打包/解包三个整数的基本示例:

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

 

可以通过将解压缩字段分配给变量或将结果包装在命名元组中来命名解压缩字段:

>>>
>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

 

格式字符的排序可能会对大小产生影响,因为满足对齐要求所需的填充是不同的:

>>>
>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5

 

以下格式'llh0l'在末尾指定两个填充字节,假设long在4字节边界上对齐:

>>>
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

 

这仅在原始大小和对齐生效时有效; 标准大小和对齐不强制任何对齐。

也可以看看

模 array
打包同类数据的二进制存储。
模 xdrlib
打包和拆包XDR数据。

struct模块还定义了以下类型:

class struct.Struct格式
返回一个新的Struct对象,它根据格式字符串格式写入和读取二进制数据。创建一个Struct对象并调用其方法比调用struct具有相同格式的函数更有效,因为格式字符串只需要编译一次。

注意

传递给最新格式字符串的编译版本 Struct和模块级函数被缓存,因此只使用少量格式字符串的程序不必担心重用单个 Struct实例。

编译的Struct对象支持以下方法和属性:

packv1v2… 
pack()函数相同,使用编译格式。(len(result)等于size。)
pack_into缓冲区偏移量v1v2…… 
pack_into()函数相同,使用编译格式。
unpack缓冲区
unpack()函数相同,使用编译格式。缓冲区的大小(以字节为单位)必须相等size
unpack_frombufferoffset = 0 
unpack_from()函数相同,使用编译格式。缓冲区的大小(以字节为单位,减去偏移量)必须至少为size
iter_unpack缓冲区
iter_unpack()函数相同,使用编译格式。缓冲区的大小(以字节为单位)必须是其倍数size

版本3.4中的新功能。

format
用于构造此Struct对象的格式字符串。

在版本3.7中更改:格式字符串类型现在str而不是bytes

size
计算出的struct的大小(以及因此由pack()方法生成的bytes对象)对应于format