Python 二进制文件读写实战:struct 模块与格式化字符串详解
本文详解如何利用 Python 内置 struct 模块进行结构化二进制数据的打包与解包。涵盖格式化字符串编写、字节序与对齐控制,以及 rb/wb 文件模式的操作细节。提供标准代码示例与常见报错排查方案,帮助开发者高效处理底层数据流,彻底规避文本模式导致的截断与跨平台换行符转换问题。
为什么需要专用二进制处理模式
Python 原生数据类型在内存中以特定结构存储,当需要将其持久化或与 C/C++ 结构体交互时,必须转换为定长字节流。直接使用文本模式(r/w)打开文件会触发操作系统的隐式编码转换,导致特定字节被误判为结束符或发生长度偏移。使用 struct 模块配合二进制文件模式(rb/wb)可实现精确到字节的无损读写。
第1步:定义格式字符串并打包数据
目的:将 Python 基本类型按固定规则压缩为连续的二进制字节序列。
入口:导入 import struct。
动作:调用 struct.pack(fmt, values),传入格式字符串与对应参数。格式字符串由数字前缀与类型字符组成,如 5s 表示 5 字节字符串,i 表示 4 字节整数。注意:原始草稿中使用 'i' 打包浮点数会导致截断或异常,此处已修正为 'd'(双精度)或 'f'(单精度)以兼容小数。
重要参数:fmt 需严格匹配后续 unpack 的顺序与长度。
完成状态:函数返回一个仅包含原始字节(不可见字符)的 bytes 对象,无额外转义标记。
import struct
# 准备混合类型数据
name = b"hello"
count = 2
value = 45.123
# 打包:'5sif' 依次对应 5字节字符串、整型、单精度浮点
data_bytes = struct.pack("5sif", name, count, value)
print(data_bytes) # 输出形如 b'hello\x00\x02\x00\x00@<...' 的字节流
第2步:以 wb/rb 模式执行文件读写
目的:绕过 Python 默认的文本缓冲与字符集检测,直接对磁盘扇区进行字节级操作。
入口:内置 open() 函数。
动作:使用 open(filepath, "wb") 写入,open(filepath, "rb") 读取。
风险提示:"wb" 模式会在打开瞬间清空目标文件原有内容。若用于增量保存或归档,请务必先确认文件权限,或对源数据进行备份,防止不可逆覆盖。
完成状态:成功关闭文件句柄后,磁盘文件大小与打包后的字节数完全一致。
# 写入二进制文件
with open("sample.bin", "wb") as binfile:
binfile.write(data_bytes)
# 读取二进制文件
with open("sample.bin", "rb") as binfile:
raw_data = binfile.read()
第3步:读取字节流并解包还原
目的:将磁盘读出的原始字节按原规则还原为可读的 Python 变量。
入口:确保已通过 read() 获取完整字节块。
动作:调用 struct.unpack(fmt, raw_data)。该函数强制返回一个元组(tuple)。若只解包单个值,必须通过切片或逗号语法提取:(val,) = struct.unpack(...) 或 val, = struct.unpack(...)。
重要参数:fmt 必须与打包时的格式严格对称。
完成状态:变量类型恢复为初始设定,数值精确匹配。
# 解包还原
n, c, v = struct.unpack("5sif", raw_data)
print(n, c, v) # 输出: b'hello' 2 45.123
核心参数对照表
1. 格式化字符(Format Codes)
| Format | C Type | Python | 字节数 |
|---|---|---|---|
x | pad byte | no value | 1 |
c | char | string of length 1 | 1 |
b | signed char | integer | 1 |
B | unsigned char | integer | 1 |
? | _Bool | bool | 1 |
h | short | integer | 2 |
H | unsigned short | integer | 2 |
i | int | integer | 4 |
I | unsigned int | integer or long | 4 |
l | long | integer | 4 |
L | unsigned long | long | 4 |
q | long long | long | 8 |
Q | unsigned long long | long | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | string | 变长 |
2. 字节序与对齐前缀(放在 fmt 首位)
| Character | Byte order | Size and alignment |
|---|---|---|
@ | native | Native padding, 凑够 4 个字节对齐 |
= | native | Standard size, 按原字节数无填充 |
< | little-endian | Standard size, 小端字节序 |
> | big-endian | Standard size, 大端字节序 |
! | network (= big-endian) | Standard size, 网络字节序 |
使用方法:将前缀拼接至格式串开头,例如 <5sif 表示采用小端模式、无自然对齐填充的字符串-整数-浮点组合。
常见报错与排错指南
- EOFError / 读取截断:若在 Windows 下使用文本模式
r读取含有0x1A(ASCII 控制字符 ZOW)的数据,解析器会提前判定为文件结束。切换至rb后可恢复完整读取。 - 长度不一致:Windows 文本模式写入时会隐式将
0x0A(LF)扩展为0x0D 0x0A(CRLF),导致文件体积增加。二进制模式wb/rb保持绝对原始字节,不会发生此类扩写。Linux/macOS 默认不转换换行符,跨平台交换数据时务必统一使用二进制模式。 - Unpack 返回元组未解包:直接赋值
a = struct.unpack("i", b)会得到(12,)。正确做法是使用逗号拆分a, = struct.unpack("i", b)或直接索引a[0]。
简要总结
通过 struct 模块的格式字符串映射与二进制 I/O 结合,Python 能够安全、高效地替代底层语言处理定长数据包。掌握 pack/unpack 的对称性、字节序前缀的选择以及 rb/wb 的物理读写特性,即可彻底解决文件损坏、数据错位与跨平台兼容性难题。以上就是使用 Python 进行二进制文件读写的详细内容,更多关于 Python 基础操作与文件处理的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









