如何将文件中存储的C结构体数据读取到Python数据类中?
如何将文件中存储的C结构体数据读取到Python数据类中?
当然有比手动字节偏移更优雅的方案啦!不用再对着字节数一点点算位置,我们可以结合Python标准库和数据类的特性来实现,甚至可以用装饰器把逻辑封装得更整洁。
方法一:用struct模块+数据类工厂方法
Python的struct模块专门用来处理C风格的字节结构,我们可以给数据类添加一个类方法,直接从文件读取并解析数据:
首先导入必要的模块:
from dataclasses import dataclass import struct
然后定义你的数据类并添加解析方法:
@dataclass class Boh: a: int b: int c: bool @classmethod def from_file(cls, file_path): # 格式字符串说明: # <:小端字节序(如果写入文件时用的是大端,换成>;本机字节序用=) # I:对应C的uint32_t(4字节无符号整数) # b:对应C的int8_t(1字节有符号整数) # ?:对应C的bool/boolean(1字节布尔值) format_str = '<I b ?' with open(file_path, 'rb') as f: # 读取刚好对应结构体大小的字节 raw_data = f.read(struct.calcsize(format_str)) # 解析字节为对应的值 a_val, b_val, c_val = struct.unpack(format_str, raw_data) return cls(a=a_val, b=b_val, c=c_val)
使用的时候就很简单了:
# 从文件读取并生成Boh实例 my_boh = Boh.from_file("boh_data.bin")
方法二:用装饰器封装解析逻辑(更复用)
如果你有多个结构体需要处理,写重复的工厂方法太麻烦,可以自定义一个装饰器,把struct解析逻辑封装起来,直接给数据类打个装饰器就能用:
先写装饰器:
import struct from dataclasses import dataclass def struct_dataclass(format_str): def decorator(cls): # 添加入参为字节数据的解析方法 @classmethod def from_bytes(cls, byte_data): unpacked_vals = struct.unpack(format_str, byte_data) return cls(*unpacked_vals) # 添加入参为文件路径的解析方法 @classmethod def from_file(cls, file_path): with open(file_path, 'rb') as f: byte_size = struct.calcsize(format_str) raw_data = f.read(byte_size) return cls.from_bytes(raw_data) # 把方法绑定到数据类上 cls.from_bytes = from_bytes cls.from_file = from_file return cls return decorator
然后用装饰器修饰你的数据类:
@struct_dataclass('<I b ?') @dataclass class Boh: a: int b: int c: bool
这样不管多少个结构体,只要给装饰器传入对应的格式字符串,就能直接用from_file或from_bytes方法解析了!
重要注意事项:内存对齐问题
C编译器会自动给结构体成员做内存对齐(比如为了性能,把成员对齐到4字节或8字节边界),这会导致结构体的实际大小比成员字节数之和大。比如你的struct boh,如果编译器默认对齐到4字节,那么int8_t b后面会填充3个空字节,总大小会是8字节而不是6字节。
这时候你需要调整struct的格式字符串,加上填充字节的占位符:
- 比如上面的情况,格式字符串要改成
<I b 3x ?,其中3x表示跳过3个填充字节。
你可以在C代码里用sizeof(struct boh)算出实际大小,再对比Python里struct.calcsize(format_str)的结果,如果不一致,就说明有填充,需要补充对应的x占位符。
备注:内容来源于stack exchange,提问作者Brendon Mendicino
相关产品推荐
相关产品推荐

