该模块在Python值和表示为Python bytes对象的C结缓冲区构体之间进行转换。可用于处理存储在文件中或者来自网络连接,以及其它来源的二进制数据。它使用格式化字符串,作为C结构体布局的简洁描述,以及从Python值,或者到Python值的预期转换。
注意:默认情况下,封装给定的C结构体的结构包括填充字节,以便为涉及的C类型保持正确的对齐;类似地,解包时会考虑对齐。选择此行为使得被封装的结构体的字节完全对应于C结构体在内存中的布局。要处理平台无关的数据格式,或者忽略隐式的填充字节,可以使用
standard
大小和对齐,代替native
大小和对齐,查看字节顺序,大小和对齐了解详情。
有几个struct
函数(和Struct
的方法)接收一个buffer
参数。它引用实现了Buffer
协议的对象,并提供一个可读,或可读写的缓存。用于该目的的最常见的类型是bytes
和bytearray
,但是可以视为字节数组的许多其它类型实现了Buffer
协议,因此它们可以读和填充,而不需要额外的从bytes
对象复制。
1 函数和异常
该模块定义了以下异常和函数:
1.1 异常 struct.error
在各种场合下抛出异常;参数是描述错误的字符串。
1.2 struct.pack(fmt, v1, v2, ...)
根据格式化字符串fmt
封装,返回一个包括v1
,v2
等值的字节对象。参数必须与格式化所需的值完全匹配。
1.3 struct.pack_into(ftm, buffer, offset, v1, v2, ...)
根据格式化字符串fmt
,封装v1
,v2
等值,并从位置offset
开始,将封装的字节写入可写缓冲区buffer
中。注意,offset
是必需的参数。
1.4 struct.unpack(fmt, buffer)
根据格式化字符串fmt
,从缓冲区buffer
(假设由pack(fmt, ...)
封装)中解包。即使结果只包含一项,也是一个元组。缓冲区的大小(以字节为单位)必需与格式所需的大小匹配,比如calcsize()
所得的结果。
1.5 struct.unpack_from(fmt, buffer, offset=0)
根据格式化字符串fmt
,从位置offset
开始解包。即使结果只包含一项,也是一个元组。缓冲区的大小(以字节为单位)减去offset
,至少是格式化所需的大小,比如calcsize()
所得的结果。
1.5 struct.iter_unpack(fmt, buffer)
版本3.4中新增。
根据格式化字符串fmt
,从缓冲区buffer
中迭代解包。该函数返回一个iterator
,它将从缓冲区中读取大小相等的块,直到所有内容被耗尽。缓冲区的大小(以字节为单位)必须是格式化所需大小的倍数,比如calcsize()
所得的结果。
每次迭代yield一个由格式化字符串指定的元组。
1.6 struct.calcsize(fmt)
返回对应于格式化字符串fmt
的结构体(以及由pack(fmt, ...)
生成的字节对象)的大小。
2 格式化字符串
封装和解包数据时,格式化字符串是用于指定预期布局的机制。它们由Format Characters构成,指定封装和解包的数据类型。此外,还有一些特殊字符控制字节顺序,大小和对齐。
2.1 字节顺序,大小和对齐
默认情况下,C语言类型以机器的本机格式和字节顺序表示,如果需要(根据C编译器使用的规则),跳过填充字节,以便正确对齐。
或者根据下表,格式化字符串的第一个字符用于表明封装数据的字节顺序,大小和对齐:
字符 | 字节顺序 | 大小 | 对齐 |
---|---|---|---|
@ | 本机 | 本机 | 本机 |
= | 本机 | 标准 | 无 |
< | 小端 | 标准 | 无 |
> | 大端 | 标准 | 无 |
! | 网络(等于大端) | 标准 | 无 |
如果第一个字符不是其中之一,则假定为“@”。
本地字节顺序是大端或小端,这取决于主机系统。例如,Intel x86和AMD64(x86-64)是小端字节序;摩托罗拉68000和PowerPC G5是大端字节序;ARM和Intel Itanium可切换字节顺序(双字节顺序)。使用sys.byteorder
检查系统的字节顺序。
使用C编译器的sizeof
表达式确定本机大小和对齐。这总是与本机字节顺序结合。
标准大小仅取决于格式化字符;参考格式化字符中的表格。
注意“@”和“=”之间的区别:都使用本机字节顺序;但后者的大小和对齐是标准的。
“!”形式用于忘记网络字节顺序是大端还是小端的情况。
没有办法表示非本地字节顺序(强制字节交换);使用适当的“<”或“>”。
注意:
- 填充仅在连续的结构体成员之间自动添加。在编码的结构体的开头或结尾不填充。
- 使用非本地大小和对齐时,不添加填充,比如“<”,“>”,“=”和“!”。
- 要将结构体结尾与特殊类型的对齐要求对齐,使用重复计数为0的该类型的代码结束格式。
2.2 格式化字符
版本3.1中修改:在3.0中,有些整数格式封装了超出范围的值,并抛出
DeprecationWarning
代替struct.error
。版本3.2中修改:新增为非整数使用
__index__()
方法。版本3.3中修改:添加“n”和“N”格式。
版本3.6中修改:添加“e”格式。
格式化字符有以下含义:C和Python值之间的转换应该明确指定类型。“标准大小”列表示,使用标准大小时,被封装值的字节大小;也就是格式化字符串以“<”,“>”,“!”或“=”开始时。当使用本机大小,被封装值的大小是平台相关的。
格式 | C类型 | Python类型 | 标准大小 | 提示 |
---|---|---|---|---|
x | 填充字节 | 没有值 | ||
c | char | 长度为1的字节 | 1 | |
b | signed char | integer | 1 | 1,3 |
B | unsigned char | integer | 1 | 3 |
? | _Bool | bool | 1 | 1 |
h | short | integer | 2 | 3 |
H | unsigned short | integer | 2 | 3 |
i | int | integer | 4 | 3 |
I | unsigned int | integer | 4 | 3 |
l | long | integer | 4 | 3 |
L | unsigned long | integer | 4 | 3 |
q | long long | integer | 8 | 2,3 |
Q | unsigned long long | integer | 8 | 2,3 |
n | ssize_t | integer | 4 | |
N | size_t | integet | 4 | |
e | 7 | float | 2 | 5 |
f | float | float | 4 | 5 |
d | double | float | 8 | 5 |
s | char[] | bytes | ||
p | char[] | bytes | ||
P | void * | integer | 6 |
提示:
- “?”转换码对应的
_Bool
类型由C99定义。如果该类型不可用,使用char
模拟。在标准模式下,它总是由一个字节表示。 - 只有C编译器支持
long long
类型,或者Windows上的__int64
时,“q”和“Q”转换码才在本机模式下可用。在标准模式下它们总是可用。 - 使用图任何整数转换码封装一个非整数时,如果非整数有
__index__()
方法,则在封装前会调用该方法把参数转换为整数。 - “n”和“N”转换只在本机大小中可用(选择默认或“@”字节顺序)。对于标准大小,可用使用适合应用程序的其它整数格式。
- 对于“f”,“d”和“e”转换码,封装分别表示使用IEEE 754的binary32,binary64或binary16格式,而不管平台使用的浮点数格式。
- “P”只在本机字节顺序可用(选择默认或“@”字节顺序)。“=”根据主机系统选择使用小端或大端顺序。
struct
模块不会解释为本机顺序,因此“P”格式不可用。 - IEEE 754标准的2008版本中,引入了IEEE 754 binary16半精度。它有一个符号位,5位指数和11位精度(其中10位存储),全精度可用表示大约
6.1e-05
和6.1e-05
。C编译器没有广泛支持该类型;在典型的机器中,unsigned short可用于存储,但不适合数据运算。
可以在格式化字符之前使用整数表示重复次数。例如,“4h”完全等价于“hhhh”。
尽管次数和它的格式不可能包含空格,还是会忽略格式化字符之前的空格。
对于“s”格式化字符,次数表示字节的长度,而不是其它格式化字符的重复次数;例如,“10s”表示单个10个字节的字符串,“10c”表示10个字符。如果没有指定次数,默认为1。对于封装,字符串被截断,或者用空字节填充,让其正确适应。对于解包,生成的字节对象总是指定的字节数。对于特殊情况,“0s”表示单个空字符串(“0c”表示0个字符)。
使用其中一个整数格式(“b”,“B”,“h”,“H”,“i”,“I”,“l”,“L”,“q”,“Q”)封装值x的时候,如果x超出格式的有效返回,会抛出struct.error
异常。
格式化字符“p”编码一个Pascal string
,表示一个short可变长度的字符串存储在固定字节数中,其长度由次数指定。第一个字节存储字符串的长度,或者255,取两者中的较小者。接着是字节的字符串。如果传递到pack()
中的字符串太长(长于次数减1),则只存储前count-1
个字节。如果字符串比count-1
短,则使用空字节填充,以便使用所有字节。注意,对应unpack()
,“p”格式化字符消耗count
个字节,但返回的字符串永远不会超过255个字节。
对于“?”格式化字符,返回值是True
或False
。封装时,使用参数对象的真值。在本机或标准bool
表示中,0或1会被封装,解包时任何非0值是True
。
2.3 示例
注意:所有示例假设本机字节顺序和大小,以及大端机器对齐。
封装/解包三个整数的基本示例:
>>> 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
下面的“11h01”格式,在结尾指定了两个填充字节,假设long
在4字节边界对齐:
>>> pack('11h01', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
这只在本机大小和对齐有效时才其作用;标准大小和对齐不强制任何对齐。
3 类
struct
模块还定义了以下类型:
3.1 类struct.Struct(format)
返回一个新的Struct
对象,更具格式化字符串format
写入和读取二进制数据。创建一个Struct
对象,并调用它的方法,比用同样格式调用struct
函数更高效,因为格式化字符串只需要编译一次。
编译的Struct
对象支持以下方法和属性:
3.1.1 pack(v1, v2, ...)
完全等同于pack()
函数,使用编译后的格式。(len(result)
将会等于size
)
3.1.2 pack_into(buffer, offset, v1, v2, ...)
完全等同于pack_into()
函数,使用编译后的格式。
3.1.3 unpack(buffer)
完全等同于unpack()
函数,使用编译后的格式。缓冲区的大小(以字节为单位)必须等于size
。
3.1.4 unpack_from(buffer, offset=0)
完全等同于unpack_from()
函数,使用编译后的格式。缓冲区的大小减去offset
(以字节为单位)必须至少为size
。
3.1.5 iter_unpack(buffer)
版本3.4中新增。
完全等同于iter_unpack()
函数,使用编译后的格式。缓冲区的大小(以字节为单位)必须是size
的倍数。
3.1.6 format
构造该Struct
对象的格式化字符串。
3.1.7 size
对应于format
的结构体(以及由pack(fmt, ...)
生成的字节对象)的大小。
网友评论