7.3. struct — 将字符串解释为打包的二进制数据 — Python 文档
7.3. 结构 — 将字符串解释为打包的二进制数据
该模块执行 Python 值和表示为 Python 字符串的 C 结构之间的转换。 这可用于处理存储在文件中或来自网络连接等来源的二进制数据。 它使用 Format Strings 作为 C 结构布局的紧凑描述以及与 Python 值之间的预期转换。
笔记
默认情况下,打包给定 C 结构的结果包括填充字节,以便为所涉及的 C 类型保持正确对齐; 同样,拆包时也要考虑对齐。 选择此行为是为了使打包结构的字节与相应 C 结构在内存中的布局完全对应。 要处理与平台无关的数据格式或省略隐式填充字节,请使用 standard
大小和对齐而不是 native
大小和对齐:请参阅 字节顺序、大小和对齐 细节。
7.3.1. 函数和异常
该模块定义了以下异常和函数:
- exception struct.error
- 在各种场合提出的异常; 参数是一个描述错误的字符串。
- struct.pack(fmt, v1, v2, ...)
- 返回包含根据给定格式打包的值
v1, v2, ...
的字符串。 参数必须与格式所需的值完全匹配。
- struct.pack_into(fmt, buffer, offset, v1, v2, ...)
根据给定的格式将值
v1, v2, ...
打包,将打包的字节写入可写的 缓冲区 ,从 offset 开始。 请注意,偏移量是必需的参数。2.5 版中的新功能。
- struct.unpack(fmt, string)
- 根据给定的格式解压缩字符串(大概由
pack(fmt, ...)
打包)。 结果是一个元组,即使它只包含一个项目。 该字符串必须准确包含格式所需的数据量(len(string)
必须等于calcsize(fmt)
)。
- struct.unpack_from(fmt, buffer[, offset=0])
根据给定的格式解包 缓冲区 。 结果是一个元组,即使它只包含一个项目。 buffer 必须至少包含格式所需的数据量(
len(buffer[offset:])
必须至少为calcsize(fmt)
)。2.5 版中的新功能。
- struct.calcsize(fmt)
- 返回与给定格式对应的结构(以及字符串)的大小。
7.3.2. 格式化字符串
格式字符串是用于在打包和解包数据时指定预期布局的机制。 它们由 格式字符 构成,指定被打包/解包的数据类型。 此外,还有用于控制字节顺序、大小和对齐的特殊字符。
7.3.2.1. 字节顺序、大小和对齐
默认情况下,C 类型以机器的本机格式和字节顺序表示,并在必要时通过跳过填充字节来正确对齐(根据 C 编译器使用的规则)。
或者,可以使用格式字符串的第一个字符来指示打包数据的字节顺序、大小和对齐方式,如下表所示:
特点 | 字节顺序 | 尺寸 | 结盟 |
---|---|---|---|
@
|
本国的 | 本国的 | 本国的 |
=
|
本国的 | 标准 | 没有任何 |
<
|
小端 | 标准 | 没有任何 |
>
|
大端 | 标准 | 没有任何 |
!
|
网络(=大端) | 标准 | 没有任何 |
如果第一个字符不是这些字符中的一个,则假定为 '@'
。
本机字节顺序是大端或小端,具体取决于主机系统。 例如,Intel x86 和 AMD64 (x86-64) 是小端; 摩托罗拉 68000 和 PowerPC G5 是大端; ARM 和 Intel Itanium 具有可切换的字节序(双字节序)。 使用 sys.byteorder
检查系统的字节序。
本机大小和对齐方式是使用 C 编译器的 sizeof
表达式确定的。 这总是与本机字节顺序相结合。
标准大小仅取决于格式字符; 请参阅 格式字符 部分中的表格。
注意 '@'
和 '='
的区别:两者都使用原生字节顺序,但后者的大小和对齐方式是标准化的。
形式 '!'
可用于那些声称无法记住网络字节顺序是大端还是小端的可怜人。
无法指示非本机字节顺序(强制字节交换); use the appropriate choice of '<'
or '>'
.
笔记:
- 填充仅在连续的结构成员之间自动添加。 在编码结构的开头或结尾不添加填充。
- 使用非原生大小和对齐时不添加填充,例如 带有“”、“=”和“!”。
- 要将结构的结尾与特定类型的对齐要求对齐,请使用重复计数为零的该类型的代码结束格式。 请参阅 示例 。
7.3.2.2. 格式字符
格式字符有以下含义; 考虑到它们的类型,C 和 Python 值之间的转换应该是显而易见的。 'Standard size'列是指使用标准大小时打包值的大小(以字节为单位); 即,当格式字符串以 '<'
、'>'
、'!'
或 '='
之一开头时。 使用本机大小时,打包值的大小取决于平台。
格式 | C型 | 蟒蛇型 | 标准尺寸 | 笔记 |
---|---|---|---|---|
x
|
填充字节 | 没有价值 | ||
c
|
char
|
长度为 1 的字符串 | 1 | |
b
|
signed char
|
整数 | 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) |
f
|
float
|
漂浮 | 4 | (4) |
d
|
double
|
漂浮 | 8 | (4) |
s
|
char[]
|
细绳 | ||
p
|
char[]
|
细绳 | ||
P
|
void *
|
整数 | (5), (3) |
笔记:
'?'
转换码对应C99定义的_Bool
类型。 如果此类型不可用,则使用char
进行模拟。 在标准模式下,它总是用一个字节表示。2.6 版中的新功能。
'q'
和'Q'
转换代码仅在平台 C 编译器支持 Clong long
或在 Windows 上支持__int64
时才在本机模式下可用。 它们在标准模式下始终可用。2.2 版中的新功能。
当尝试使用任何整数转换代码打包非整数时,如果非整数具有
__index__()
方法,则在打包之前调用该方法将参数转换为整数。 如果不存在__index__()
方法,或者对__index__()
的调用引发TypeError
,则尝试__int__()
方法。 但是,不推荐使用__int__()
,并且会引发DeprecationWarning
。2.7 版更改: 对非整数使用
__index__()
方法是 2.7 中的新功能。2.7 版更改: 在 2.7 版之前,并非所有整数转换代码都会使用
__int__()
方法进行转换,并且DeprecationWarning
仅针对浮点参数提出。对于
'f'
和'd'
转换代码,打包表示使用 IEEE 754 binary32(对于'f'
)或 binary64(对于'd'
)格式,不管平台使用的浮点格式。'P'
格式字符仅适用于本机字节顺序(选择为默认值或使用'@'
字节顺序字符)。 字节顺序字符'='
根据主机系统选择使用小端或大端排序。 struct 模块不会将此解释为本机排序,因此'P'
格式不可用。
格式字符前面可能有一个整数重复计数。 例如,格式字符串 '4h'
的含义与 'hhhh'
完全相同。
格式之间的空白字符被忽略; 但是,计数及其格式不得包含空格。
对于 's'
格式字符,计数被解释为字符串的大小,而不是像其他格式字符那样重复计数; 例如,'10s'
表示单个 10 字节字符串,而 '10c'
表示 10 个字符。 如果未给出计数,则默认为 1。 对于打包,字符串被截断或适当地用空字节填充以使其适合。 对于解包,结果字符串始终具有指定的字节数。 作为特殊情况,'0s'
表示单个空字符串(而 '0c'
表示 0 个字符)。
'p'
格式字符编码“Pascal 字符串”,意思是存储在 固定字节数 中的短可变长度字符串,由计数给出。 存储的第一个字节是字符串的长度,或 255,以较小者为准。 字符串的字节如下。 如果传入 pack() 的字符串太长(比计数减 1 长),则只存储字符串的前导 count-1
字节。 如果字符串比 count-1
短,则用空字节填充它,以便完全使用 count 个字节。 请注意,对于 unpack(),'p'
格式字符消耗 count 字节,但返回的字符串不能包含超过 255 个字符。
对于 'P'
格式字符,返回值是 Python 整数或长整数,这取决于在将指针转换为整数类型时保存指针所需的大小。 NULL 指针将始终作为 Python 整数 0
返回。 打包指针大小的值时,可以使用 Python 整数或长整数对象。 例如,Alpha 和 Merced 处理器使用 64 位指针值,这意味着 Python 长整数将用于保存指针; 其他平台使用 32 位指针并将使用 Python 整数。
对于 '?'
格式字符,返回值为 True 或 False。 打包时,使用参数对象的真值。 本机或标准 bool 表示中的 0 或 1 将被打包,解包时任何非零值都将是 True
。
7.3.2.3. 例子
笔记
所有示例都假定本机字节顺序、大小和与大端机器对齐。
打包/解包三个整数的基本示例:
>>> 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
解包字段可以通过将它们分配给变量或将结果包装在命名元组中来命名:
>>> record = '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='raymond ', serialnum=4658, school=264, gradelevel=8)
格式字符的排序可能会对大小产生影响,因为满足对齐要求所需的填充是不同的:
>>> pack('ci', '*', 0x12131415)
'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, '*')
'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5
以下格式 'llh0l'
在末尾指定了两个填充字节,假设 long 在 4 字节边界上对齐:
>>> pack('llh0l', 1, 2, 3)
'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
这仅在本机大小和对齐有效时才有效; 标准尺寸和对齐不强制任何对齐。
7.3.3. 班级
struct 模块还定义了以下类型:
- class struct.Struct(format)
返回一个新的 Struct 对象,它根据格式字符串 format 写入和读取二进制数据。 创建一次 Struct 对象并调用其方法比使用相同格式调用 struct 函数更有效,因为格式字符串只需要编译一次。
2.5 版中的新功能。
编译后的 Struct 对象支持以下方法和属性:
- pack(v1, v2, ...)
与 pack() 函数相同,使用编译格式。 (
len(result)
将等于self.size
。)
- pack_into(buffer, offset, v1, v2, ...)
与 pack_into() 函数相同,使用编译格式。
- unpack(string)
与 unpack() 函数相同,使用编译格式。 (
len(string)
必须等于self.size
)。
- unpack_from(buffer, offset=0)
与 unpack_from() 函数相同,使用编译格式。 (
len(buffer[offset:])
必须至少为self.size
)。
- format
用于构造此 Struct 对象的格式字符串。
- size
与 格式 对应的结构(以及字符串)的计算大小。