Python中如何将内存中的字节数组映射为结构体并按字段名访问元素?
Python中如何将内存中的字节数组映射为结构体并按字段名访问元素?
看起来你已经用O'Reilly《Python Cookbook》里的结构体工具搞定了固定长度的磁盘头和轨道信息解析,现在卡在了把内存里的sectorTable字节数组转换成可按字段名访问的结构体列表上对吧?从汇编转Python确实会有这种“直接操作内存地址”到“面向对象属性访问”的思维转换,我来给你几个简洁的方案。
方案一:初始化时拆分sectorTable为结构体实例集合
既然你已经知道每个SectorInformationBlock是8字节,而且numberOfSectors字段里有具体的数量,那可以在TrackInformationBlock的初始化方法里直接把字节数据拆分成一个个结构体实例,存成列表甚至按SectorID索引的字典,完全满足你像track.sector_by_id["C7"]这样的访问需求。
修改你的TrackInformationBlock类:
class TrackInformationBlock(Structure): _fields_ = [ ('<12s','header'), ('<4s','unused'), ('b','TrackNumber'), ('b','TrackSide'), ('h','unused2'), ('b','sectorSize'), ('b','numberOfSectors'), ('b','gap3'), ('b','filler'), ('<232s','sectorTable') ] def __init__(self, bytedata): super().__init__(bytedata) # 拆分sectorTable为SectorInformationBlock实例列表 self.sectors = [] sector_struct_size = SectorInformationBlock.struct_size # 每个sector结构体的固定大小(8字节) for i in range(self.numberOfSectors): start_idx = i * sector_struct_size end_idx = start_idx + sector_struct_size sector_byte_data = self.sectorTable[start_idx:end_idx] self.sectors.append(SectorInformationBlock(sector_byte_data)) # 额外:生成按SectorID索引的字典,方便直接按ID访问 self.sector_by_id = {} for sector in self.sectors: # 将SectorID转为十六进制字符串格式,比如0xC1转成'C1' sector_id_hex = f"{sector.SectorID:02X}" self.sector_by_id[sector_id_hex] = sector
这样修改后,你就可以:
- 按顺序访问单个sector:
track.sectors[0].SectorID - 直接按SectorID访问:
track.sector_by_id['C7'].Track
完全不用再手动计算切片位置,代码也更符合Python的简洁风格。
方案二:用迭代器按需解析(适合大文件场景)
如果担心一次性解析所有sector占用内存(比如处理超大磁盘镜像时),可以给TrackInformationBlock加一个迭代方法,每次返回一个SectorInformationBlock实例:
class TrackInformationBlock(Structure): # 保持原有_fields_定义不变 _fields_ = [ ('<12s','header'), ('<4s','unused'), ('b','TrackNumber'), ('b','TrackSide'), ('h','unused2'), ('b','sectorSize'), ('b','numberOfSectors'), ('b','gap3'), ('b','filler'), ('<232s','sectorTable') ] def iter_sectors(self): sector_struct_size = SectorInformationBlock.struct_size for i in range(self.numberOfSectors): start_idx = i * sector_struct_size end_idx = start_idx + sector_struct_size yield SectorInformationBlock(self.sectorTable[start_idx:end_idx])
使用的时候可以直接遍历:
for sector in track.iter_sectors(): print(f"Sector ID: {sector.SectorID:02X}, Track: {sector.Track}")
复用现有工具类的简化方案
你已经引入的SizedRecord类里其实有iter_as方法可以直接处理这种场景,完全可以复用它来快速生成sector结构体列表:
# 假设你已经有一个TrackInformationBlock实例track # 把sectorTable转换成SectorInformationBlock实例列表 sectors = list(memoryview(track.sectorTable).iter_as(SectorInformationBlock)) # 转成按SectorID索引的字典 sector_by_id = {f"{s.SectorID:02X}": s for s in sectors}
这种方式能保持你现有代码的一致性,不用额外修改结构体类。
备注:内容来源于stack exchange,提问作者Jason Brooks
相关产品推荐
相关产品推荐

