Python struct模块与二进制数据解析

📅 2026/6/16 16:57:45
Python struct模块与二进制数据解析
Python struct模块与二进制数据解析struct模块在Python值和C结构体之间转换字节。pack将Python值打包为字节unpack将字节解包为Python值。import struct# 打包整数42打包为大端序4字节有符号整数packed struct.pack(i, 42)print(packed) # b\x00\x00\x00*# 解包value struct.unpack(i, packed)print(value[0]) # 42格式字符指定字节序和类型。表示大端序i表示有符号int。表示小端序!表示网络字节序。字节序的含义import structvalue 0x01020304print(struct.pack(i, value)) # 大端序: b\x01\x02\x03\x04print(struct.pack( print(struct.pack(!i, value)) # 网络序(大端): b\x01\x02\x03\x04大端序高字节在低地址。小端序低字节在低地址。网络协议通常使用大端序x86使用小端序。格式字符说明import struct# 各种类型的打包print(struct.pack(b, 127)) # signed charprint(struct.pack(B, 255)) # unsigned charprint(struct.pack(h, 32767)) # shortprint(struct.pack(H, 65535)) # unsigned shortprint(struct.pack(i, 2**31-1)) # intprint(struct.pack(I, 2**32-1)) # unsigned intprint(struct.pack(q, 2**63-1)) # long longprint(struct.pack(Q, 2**64-1)) # unsigned long longprint(struct.pack(f, 3.14159)) # floatprint(struct.pack(d, 3.141592653589793)) # double格式字符大小b1, h2, i4, q8, f4, d8字节。Struct对象预编译格式字符串提升性能import struct# 预编译格式字符串my_struct struct.Struct(3i2d)print(my_struct.size) # 3*4 2*8 28字节# 使用预编译对象进行打包解包data my_struct.pack(1, 2, 3, 1.0, 2.0)values my_struct.unpack(data)# pack_into和unpack_from操作缓冲区import ctypesbuf ctypes.create_string_buffer(my_struct.size)my_struct.pack_into(buf, 0, 1, 2, 3, 1.0, 2.0)values my_struct.unpack_from(buf, 0)Struct对象预编译格式提升频繁打包解包场景的性能。变长字符串的处理import struct# 固定长度字符串name bAlicedata struct.pack(5s, name)print(struct.unpack(5s, data)) # (bAlice,)# 前导长度的字符串Pascal风格length len(name)data struct.pack(fB{length}s, length, name)# 先读长度再读字符串length data[0]name data[1:1length]struct不支持变长字段需要手动处理。解析TCP协议头import structdef parse_tcp_header(data):# TCP头固定20字节src_port, dst_port, seq, ack_seq, offset_reserved, flags, window, checksum, urg_ptr \struct.unpack(!HHIIBBHHH, data[:20])data_offset (offset_reserved 4) * 4ns (offset_reserved 3) 1cwr (flags 7) 1ece (flags 6) 1urg (flags 5) 1ack (flags 4) 1psh (flags 3) 1rst (flags 2) 1syn (flags 1) 1fin flags 1return {src_port: src_port, dst_port: dst_port, seq: seq,ack_seq: ack_seq, data_offset: data_offset,flags: {ns: ns, cwr: cwr, ece: ece, urg: urg,ack: ack, psh: psh, rst: rst, syn: syn, fin: fin},window: window, checksum: checksum, urg_ptr: urg_ptr}TCP头解析展示了位操作在协议解析中的实际应用。填充和对齐import struct# 自然对齐默认packed struct.pack(ci, bA, 0x01020304)print(packed.hex()) # 4100000001020304有3字节填充# 取消对齐packed struct.pack(ci, bA, 0x01020304)print(packed.hex()) # 4101020304无填充# 显式填充packed struct.pack(cxi, bA, 0x01020304)取消对齐使用本地对齐默认。x插入一个填充字节。二进制文件解析实战import structclass BMPHeader:staticmethoddef parse(data):header struct.unpack(2sI4HIHHI, data[:30])return {signature: header[0], # bBMfile_size: header[1], # 文件大小reserved1: header[2],reserved2: header[3],data_offset: header[4], # 像素数据偏移header_size: header[5], # BITMAPINFOHEADER大小width: header[6], # 宽度height: header[7], # 高度planes: header[8], # 颜色平面数bits_per_pixel: header[9], # 每像素位数}with open(image.bmp, rb) as f:header BMPHeader.parse(f.read(30))print(fWidth: {header[width]}, Height: {header[height]})print(fBPP: {header[bits_per_pixel]})BMP文件头的解析展示了struct在实际文件格式处理中的应用。大端序与小端序的检测import structimport sysprint(sys.byteorder) # little (x86)# 打包1检查字节序测试test struct.pack(H, 1)if test b\x01\x00:print(小端序)elif test b\x00\x01:print(大端序)struct.calcsize计算格式字符串的大小import structsizes {char: struct.calcsize(c),byte: struct.calcsize(b),short: struct.calcsize(h),int: struct.calcsize(i),long: struct.calcsize(l),long_long: struct.calcsize(q),float: struct.calcsize(f),double: struct.calcsize(d),pointer: struct.calcsize(P),}print(sizes)calcsize用于预分配缓冲区或校验格式长度。struct模块的性能基准import structimport timeitdef pack_bench():for _ in range(100000):struct.pack(3i2d, 1, 2, 3, 1.0, 2.0)def unpack_bench():data struct.pack(3i2d, 1, 2, 3, 1.0, 2.0)for _ in range(100000):struct.unpack(3i2d, data)print(fpack: {timeit.timeit(pack_bench, number10)/10:.4f}s)print(funpack: {timeit.timeit(unpack_bench, number10)/10:.4f}s)