Python struct模块详解:二进制数据的打包与解包实践
Python标准库中的struct模块专用于二进制数据的打包与解包,广泛适用于网络通信、底层协议解析及C语言结构体交互。本文系统讲解format格式映射、字节序控制前缀,演示pack与unpack核心流程,并提供calcsize、缓冲流写入及Struct预编译优化方案,助力开发者高效处理定长字节流。
二进制数据的打包与解包基础
在处理非文本形式的底层数据交换时,Python内置的struct模块能够精确地将Python原生数据类型转换为固定长度的字节流(bytes),或将字节流还原为Python对象。该过程主要依赖两大核心函数:pack负责序列化打包,unpack负责反序列化解包。
第1步:掌握基础打包语法与格式映射
struct.pack的标准调用格式为struct.pack(format, v1, v2, ...)。其中format是决定转换规则的格式字符串,v1至vN是需要转换的Python对象,返回值即为转换后的bytes实例。
>>> import struct
>>> struct.pack('i', 15)
b'\x0f\x00\x00\x00'
>>> struct.pack('iii', 15, 16, 17)
b'\x0f\x00\x00\x00\x10\x00\x00\x00\x11\x00\x00\x00'
>>> struct.pack('b', 255)
struct.error: byte format requires -128 <= number <= 127
>>> struct.pack('B', 200)
b'\xc8'
>>> struct.pack('B', 71)
b'G'
上述示例中,i代表有符号整型(int),数字15被转换为占据4个字节的小端序字节串。当连续使用iii时,表示连续打包三个整数。b和B分别对应1字节有符号和无符号字符,当传入越界数值时会触发struct.error。
格式字符串中的字母严格对应底层存储结构,常用类型映射如下:
| 格式符 | C语言类型 | 说明 | 标准大小(字节) |
|---|---|---|---|
b / B | signed char / unsigned char | 有符号/无符号单字节 | 1 |
h / H | short / unsigned short | 有符号/无符号短整型 | 2 |
i / I | int / unsigned int | 有符号/无符号常规整型 | 4 |
l / L | long / unsigned long | 有符号/无符号长整型 | 4 |
q / Q | long long / unsigned long long | 8字节整型 | 8 |
n / N | ssize_t / size_t | 系统指针长度整型 | 变长 |
e | - | IEEE 754半精度浮点数 | 2 |
f | float | 4字节浮点数 | 4 |
d | double | 8字节双精度浮点数 | 8 |
c | char | 长度为1的字节串 | 动态 |
s / p | char[] / packed char[] | 字符串/帕斯卡字符串 | 动态 |
? | _Bool | 布尔值 | 1 |
x | - | 填充字节(不产生实际值) | 动态 |
第2步:配置字节序与对齐规则
不同架构CPU对多字节数据的存储顺序不同,struct支持通过格式字符串的首位字符指定编码时的字节序(Endianness)与内存对齐方式。默认情况下使用@,即采用本机的原生字节序与对齐规则。
>>> struct.pack(">i", 15)
b'\x00\x00\x00\x0f'
>>> struct.pack("<i", 15)
b'\x0f\x00\x00\x00'
常用的对齐前缀含义如下:
@:本机字节序,原样使用C结构体对齐规则。=:本机字节序,但取消填充对齐(Packed size),相邻变量紧凑排列。<:小端序(Little-endian),低地址存低位字节,常见于x86/x64架构。>:大端序(Big-endian),低地址存高位字节。!:网络字节序(等同大端序),适用于TCP/IP网络协议传输。
第3步:获取占用空间与执行缓冲流操作
在实际解析未知协议或分配内存缓冲区时,calcsize可直接根据格式串计算出打包后占用的确切字节数:
>>> struct.calcsize('B')
1
>>> struct.calcsize('i')
4
>>> struct.calcsize('III')
12
若需避免频繁创建临时字节串以提升内存效率,可使用pack_into与unpack_from直接读写预设的缓冲区(Buffer):
# 将数据写入 buffer 的 offset 偏移处
struct.pack_into(format, buffer, offset, v1, v2, ...)
# 从 buffer 的 offset 偏移处依次读取
struct.unpack_from(format, buffer, offset=0)
对于同一格式多次打包的场景,推荐实例化Struct类进行预编译,内部会自动缓存编译后的字节码与结构信息:
>>> s = struct.Struct("III")
>>> s.pack(1, 2, 3)
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
>>> s.size
12
异常排查与注意事项
在使用struct模块时,最常见的运行时异常源于数据类型越界或格式串与实际数据量不匹配。例如使用'b'格式打包超出-128 ~ 127区间的整数会抛出struct.error。此外,unpack解包时必须保证传入的字节流长度严格等于calcsize计算的预期长度,否则同样会触发尺寸不匹配错误。
总结
通过掌握格式字符串的映射规则、灵活切换字节序前缀,并利用Struct类与缓冲函数优化读写性能,开发者即可在Python中稳健地完成各类定长二进制流的序列化与反序列化工作。以上就是Python struct模块进行二进制打包与解包的详细内容,更多关于Python基础编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









