struct 模块用于在 Python 值与 C 结构体之间进行转换,常用于处理二进制数据(如文件、网络协议等)。以下是主要用法:
1. 基本格式字符 常用类型代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import structb = struct.pack('b' , -1 ) B = struct.pack('B' , 255 ) h = struct.pack('h' , -32768 ) H = struct.pack('H' , 65535 ) i = struct.pack('i' , -1 ) I = struct.pack('I' , 4294967295 ) q = struct.pack('q' , -1 ) Q = struct.pack('Q' , 18446744073709551615 ) f = struct.pack('f' , 3.14 ) d = struct.pack('d' , 3.14159 ) s = struct.pack('5s' , b'hello' )
与C/C++类型的对应关系
Python struct
C/C++ 类型
条件/平台
大小(字节)
b
int8_t
所有平台
1
B
uint8_t
所有平台
1
h
int16_t
所有平台
2
H
uint16_t
所有平台
2
i
int32_t
所有平台
4
l
int32_t 或 int64_t
平台相关
32位系统为 4 字节,64位系统通常为 8 字节
I
uint32_t
所有平台
4
L
uint32_t 或 uint64_t
平台相关
32位系统为 4 字节,64位系统通常为 8 字节
q
int64_t
所有平台
8
Q
uint64_t
所有平台
8
n
ssize_t 或intptr_t
平台相关
Python 3.3+之后才支持。32位系统为 4 字节,64位系统通常为 8 字节
N
size_t 或 uintptr_t
平台相关
Python 3.3+之后才支持。32位系统为 4 字节,64位系统通常为 8 字节
P
void* 或 uintptr_t
平台相关
指针数据,32位系统为 4 字节,64位系统通常为 8 字节
s
char[]
所有平台
固定长度的字符串,如10s表示10个字符的字符串
2. 基本操作 打包(pack) 1 2 3 4 5 import structdata = struct.pack('i f 5s' , 10 , 3.14 , b'hello' ) print (data)
解包(unpack) 1 2 3 4 5 6 7 8 packed_data = struct.pack('i f 5s' , 10 , 3.14 , b'hello' ) values = struct.unpack('i f 5s' , packed_data) print (values) size = struct.calcsize('i f 5s' ) print (f"Size: {size} bytes" )
3. 字节序与对齐 字节序前缀 :
@:原生(默认)
<:小端(x86, ARM LE)
>:大端(网络字节序,PowerPC)
!:网络字节序(同 >)
举例:
1 2 3 4 5 6 7 8 9 10 11 12 import structvalue = 0x12345678 native = struct.pack('I' , value) little = struct.pack('<I' , value) big = struct.pack('>I' , value) network = struct.pack('!I' , value) print (f"Little endian: {little.hex ()} " )print (f"Big endian: {big.hex ()} " )
4. 高级用法 使用 Struct 对象(多次使用相同格式时更高效) 1 2 3 4 5 6 7 8 9 10 11 import structs = struct.Struct('i f 5s' ) packed = s.pack(10 , 3.14 , b'hello' ) unpacked = s.unpack(packed) print (unpacked)
处理变长数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def pack_string (s ): data = s.encode('utf-8' ) length = len (data) return struct.pack(f'I {length} s' , length, data) def unpack_string (data ): length, = struct.unpack('I' , data[:4 ]) s, = struct.unpack(f'{length} s' , data[4 :4 +length]) return s.decode('utf-8' ) packed = pack_string("Hello World!" ) print (unpack_string(packed))
5. 实际应用示例 示例1:解析 BMP 文件头 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import structdef parse_bmp_header (filename ): with open (filename, 'rb' ) as f: data = f.read(54 ) header = struct.unpack('<2s I H H I' , data[:14 ]) file_type, file_size, _, _, data_offset = header info = struct.unpack('<I i i H H I I I I I I' , data[14 :54 ]) header_size, width, height, planes, bits_per_pixel = info[:5 ] return { 'file_type' : file_type.decode(), 'width' : width, 'height' : height, 'bits_per_pixel' : bits_per_pixel }
示例2:网络协议数据包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import structimport socketdef create_packet (seq_num, data ): """创建简单的数据包:序号(4字节) + 长度(4字节) + 数据""" data_bytes = data.encode('utf-8' ) length = len (data_bytes) return struct.pack('!I I' , seq_num, length) + data_bytes def parse_packet (packet ): """解析数据包""" seq_num, length = struct.unpack('!I I' , packet[:8 ]) data = packet[8 :8 +length].decode('utf-8' ) return seq_num, data packet = create_packet(1 , "Hello, World!" ) print (parse_packet(packet))
示例3:处理二进制数据文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import structwith open ('data.bin' , 'wb' ) as f: for i in range (5 ): f.write(struct.pack('i f' , i, i * 1.5 )) with open ('data.bin' , 'rb' ) as f: while True : chunk = f.read(8 ) if not chunk: break i, f_val = struct.unpack('i f' , chunk) print (f"i={i} , f={f_val} " )
6. 常见格式字符串模式 1 2 3 4 5 6 7 8 9 format_strings = { 'int_float' : 'i f' , 'rgb_pixel' : 'BBB' , 'rgba_pixel' : 'BBBB' , 'vector3' : 'f f f' , 'header' : '<I I 16s' , 'network_packet' : '!H H I' , }
注意事项
字节序很重要 :确保打包和解包使用相同的字节序
大小端问题 :x86是小端,网络传输通常用大端
内存对齐 :C结构体可能有对齐,使用 @ 格式时会考虑对齐
Python整数无大小限制 ,但打包到固定大小时可能溢出
字符串处理 :s 格式用于字节串,不是Unicode字符串
通过 struct 模块,Python可以方便地与底层二进制数据进行交互,这在处理文件格式、网络协议、硬件接口等方面非常有用。