二进制数据服务模块之struct – 将字节解释为压缩二进制数据(18) – Python语言(必读进阶学习教程)(参考资料)
本章描述的模块提供了一些用于操作二进制数据的基本服务操作。有关二进制数据的其他操作,特别是与文件格式和网络协议相关的操作,在相关章节中进行了描述。
文本处理服务中描述的一些库也适用于与 ASCII 兼容的二进制格式(例如,re
)或所有二进制数据(例如,difflib
)。
此外,请参阅二进制序列类型中有关 Python 内置二进制数据类型的文档 ——字节、字节数组、内存视图。
此模块执行Python值和表示为Python bytes
对象的C结构之间的转换。这可用于处理存储在文件中的二进制数据或来自网络连接以及其他来源。它使用 Format Strings作为C结构布局的简洁描述以及与Python值的预期转换。
注意
默认情况下,打包给定C结构的结果包括填充字节,以便维护所涉及的C类型的正确对齐; 类似地,在拆包时考虑对齐。选择此行为是为了使压缩结构的字节与相应C结构的内存中的布局完全对应。要处理与平台无关的数据格式或省略隐式填充字节,请使用standard
大小和对齐而不是 native
大小和对齐:有关详细信息,请参阅字节顺序,大小和对齐。
几个struct
函数(和 的方法Struct
)采用缓冲区 参数。这是指实现缓冲区协议并提供可读或可读写缓冲区的对象。用于该目的的最常见类型是bytes
and bytearray
,但许多其他可以被视为字节数组的类型都实现了缓冲区协议,因此无需从bytes
对象进行额外复制即可读取/填充它们。
函数和异常
该模块定义了以下异常和函数:
exceptionstruct.
error
- 在各种场合提出异常;参数是一个描述错误的字符串。
struct.
formatpack(
v1,
v2,
…,
)
- 返回一个字节对象,其中包含根据格式字符串格式打包的值v1、v2 、 …。参数必须与格式要求的值完全匹配。
struct.
formatpack_into(
buffer,
offset,
v1,
v2,
…,
)
- 根据格式字符串格式打包值v1,v2 ,……并将打包的字节写入从位置offset开始的可写缓冲区缓冲区。请注意,偏移量是必需的参数。
struct.
formatunpack(
buffer,
)
- 根据格式字符串format从缓冲缓冲区中解包(推测由 打包) 。结果是一个元组,即使它只包含一个项目。缓冲区的字节大小必须与格式所需的大小相匹配,如.
pack(format, ...)
calcsize()
struct.
formatunpack_from(
buffer,
offset=0,
)
- 根据格式字符串格式,从位置偏移开始的缓冲区解包。结果是一个元组,即使它只包含一个项目。缓冲区的大小(以字节为单位)减去offset后,必须至少是格式所需的大小,如.
calcsize()
struct.
formatiter_unpack(
buffer,
)
- 根据格式字符串format从缓冲区缓冲区中迭代解包。这个函数返回一个迭代器,它将从缓冲区中读取相同大小的块,直到它的所有内容都被消耗完。缓冲区的字节大小必须是格式所需大小的倍数,如.
calcsize()
每次迭代都会产生一个由格式字符串指定的元组。
3.4 版中的新功能。
struct.
formatcalcsize(
)
- 返回与格式字符串format对应的结构体(以及由此产生的字节对象)的大小 。
pack(format, ...)
格式化字符串
格式字符串是用于在打包和解包数据时指定预期布局的机制。它们是从Format Characters构建的,它指定了被打包/解包的数据类型。此外,还有用于控制字节顺序、大小和对齐的特殊字符。
字节顺序、大小和对齐
默认情况下,C 类型以机器的本机格式和字节顺序表示,并在必要时通过跳过填充字节来正确对齐(根据 C 编译器使用的规则)。
或者,格式字符串的第一个字符可用于指示打包数据的字节顺序、大小和对齐方式,如下表所示:
字符 | 字节顺序 | 尺寸 | 对准 |
---|---|---|---|
@ |
本地人 | 本地人 | 本地人 |
= |
本地人 | 标准 | 没有 |
< |
小尾数 | 标准 | 没有 |
> |
大端 | 标准 | 没有 |
! |
网络(=大端) | 标准 | 没有 |
'@'
则假定。本机字节顺序是大端或小端,具体取决于主机系统。例如,Intel x86 和 AMD64 (x86-64) 是 little-endian;摩托罗拉 68000 和 PowerPC G5 是大端;ARM 和 Intel Itanium 具有可切换的字节序(双字节序)。用于sys.byteorder
检查系统的字节顺序。
本机大小和对齐方式是使用 C 编译器的 sizeof
表达式确定的。这总是与本机字节顺序相结合。
标准大小仅取决于格式字符;请参阅格式字符部分中的表格。
'@'
注意和之间的区别'='
:两者都使用本机字节顺序,但后者的大小和对齐方式是标准化的。
该表格'!'
适用于那些声称他们不记得网络字节顺序是大端还是小端的可怜人。
无法指示非本机字节顺序(强制字节交换);使用适当的OR'<'
选择'>'
。
笔记:
- 填充仅在连续结构成员之间自动添加。在编码结构的开头或结尾处不添加任何填充。
- 使用非原生大小和对齐方式时不添加填充,例如使用“<”、“>”、“=”和“!”。
- 要将结构的结尾与特定类型的对齐要求对齐,请以该类型的代码结束格式,并且重复计数为零。请参阅示例。
格式化字符
格式字符具有以下含义;考虑到它们的类型,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) |
-
'?'
转换代码对应于_Bool
C99 定义的类型。如果此类型不可用,则使用char
. 在标准模式下,它总是用一个字节表示。 - 尝试使用任何整数转换代码打包非整数时,如果非整数有
__index__()
方法,则调用该方法以在打包前将参数转换为整数。在 3.2 版更改:在 3.2 中使用
__index__()
非整数方法是新的。 - 和转换代码仅适用于本机大小(选择为默认值或使用
'n'
字节顺序字符)。对于标准大小,您可以使用适合您的应用程序的任何其他整数格式。'N'
'@'
- 对于
'f'
、'd'
和'e'
转换代码,打包表示使用 IEEE 754 binary32、binary64 或 binary16 格式(分别用于'f'
或'd'
)'e'
,而不管平台使用的浮点格式如何。 'P'
格式字符仅可用于本机字节顺序(选择为默认值或使用字节'@'
顺序字符)。字节顺序字符'='
根据主机系统选择使用小端或大端排序。struct 模块不会将此解释为原生排序,因此该'P'
格式不可用。- IEEE 754 binary16“半精度”类型是在IEEE 754 标准的 2008 年修订版中引入的。它有一个符号位、一个 5 位指数和 11 位精度(显式存储 10 位),并且可以表示近似精度
6.1e-05
和6.5e+04
全精度之间的数字。C 编译器不广泛支持这种类型:在典型的机器上,无符号的 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'
“Pascal 字符串”进行编码,这意味着存储在固定字节数中的短可变长度字符串,由计数给出。存储的第一个字节是字符串的长度,或 255,以较小者为准。字符串的字节如下。如果传入的字符串 pack()
太长(长于 count 减 1),则只 count-1
存储字符串的前导字节。如果字符串短于 count-1
,则用空字节填充它,以便使用精确计数的字节。请注意,对于unpack()
,'p'
格式字符会消耗 count
字节,但返回的字符串不能包含超过 255 个字节。
对于'?'
格式字符,返回值为True
或 False
。打包时使用参数对象的真值。本机或标准布尔表示中的 0 或 1 将被打包,并且任何非零值将True
在解包时。
示例
打包/解包三个整数的基本示例:
>>> >>> 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'
这仅在原始大小和对齐生效时有效; 标准大小和对齐不强制任何对齐。
也可以看看
- Module
array
- 打包同类数据的二进制存储。
- Module
xdrlib
- 打包和拆包XDR数据。
类
class struct
模块还定义了以下类型:
class struct.
formatStruct(
)
- 返回一个新的 Struct 对象,该对象根据格式字符串format写入和读取二进制数据。一次创建一个 Struct 对象并调用它的方法比调用
struct
具有相同格式的函数更有效,因为格式字符串只需要编译一次。笔记
传递给的最新格式字符串的编译版本
Struct
和模块级函数被缓存,因此仅使用少数格式字符串的程序不必担心重用单个Struct
实例。编译后的 Struct 对象支持以下方法和属性:
v1pack(
v2,
…,
)
- 与函数相同
pack()
,使用编译格式。(len(result)
将等于size
。)
bufferpack_into(
offset,
v1,
v2,
…,
)
- 与函数相同
pack_into()
,使用编译格式。
bufferunpack(
)
- 与函数相同
unpack()
,使用编译格式。缓冲区的大小(以字节为单位)必须等于size
。
bufferunpack_from(
offset=0,
)
- 与函数相同
unpack_from()
,使用编译格式。缓冲区的大小(以字节为单位)减去offset后必须至少为size
.
bufferiter_unpack(
)
- 与函数相同
iter_unpack()
,使用编译格式。缓冲区的字节大小必须是 的倍数size
。3.4 版中的新功能。
format
- 用于构造此 Struct 对象的格式字符串。
在 3.7 版更改:格式字符串类型现在
str
是bytes
.
size
- 对应于 的结构体(以及由此
pack()
方法产生的字节对象)的计算大小format
。