import struct, itertools if __name__ == "__main__": # 有时候,我们需要将一系列嵌套的可变长度记录与二进制编码之间做一些转换 polys = [ [(1.0, 2.5), (3.5, 4.0), (2.5, 1.5)], [(7.0, 1.2), (5.1, 3.0), (0.5, 7.5), (0.8, 9.0)], [(3.4, 6.3), (1.2, 0.5), (4.6, 9.2)] ] # 现在我们需要将它组织成下面这样的二进制结构 # 文件头 """ 字节 类型 描述 0 int 文件代码(0x1234,小端) 4 double x的最小值(小端) 12 double y的最小值(小端) 20 double x的最大值(小端) 28 double y的最大值(小端) 36 int 三角形数量(小端) """ # 文件内容 """ 字节 类型 描述 0 int 记录长度(N字节) 4-N Points (X,Y)坐标,以浮点数表示 """ # 正常情况下,我们通过文件的具体结构来组织二进制文件的写入和读取 def write_ploys(filename, ploys): # 将嵌套的多个点列表展开变成一个大的点列表 flattened = list(itertools.chain(*ploys)) min_x = min(x for x, y in flattened) min_y = min(y for x, y in flattened) max_x = max(x for x, y in flattened) max_y = max(y for x, y in flattened) with open(filename, 'wb') as f: # 将数据按结构写入结构体中打包写入文件 f.write(struct.pack('', '!', '@')): byte_order = format[0] format = format[1:] format = byte_order + format setattr(self, field_name, StructField(format, offset)) offset += struct.calcsize(format) setattr(self, 'struct_size', offset) # 改进的structure类 class Structure_v2(metaclass=StructureMeta): def __init__(self, bytedata): self._buffer = memoryview(bytedata) # 类的方法,在实例化以后才能被调用 @classmethod def from_file(cls, f): return cls(f.read(cls.struct_size)) # 经过修改之后我们只需要告诉类字段名称和格式就行了 class PolyHeader_v2(Structure_v2): _fields_ = [ ('', '!', '@')): byte_order = format[0] format = format[1:] format = byte_order + format setattr(self, field_name, StructField(format, offset)) offset += struct.calcsize(format) setattr(self, 'struct_size', offset) # 改进的structure类 class NestedStruct: def __init__(self, name, struct_type, offset): self.name = name self.struct_type = struct_type self.offset = offset def __get__(self, instance, cls): if instance is None: return self else: data = instance._buffer[self.offset: self.offset + self.struct_type.struct_size] result = self.struct_type(data) setattr(instance, self.name, result) return result # 改进的structure类,基础方法在init里设置memoryview来进行懒加载 class Structure_v3(metaclass=StructureMeta_v2): def __init__(self, bytedata): self._buffer = memoryview(bytedata) # 类的方法,在实例化以后才能被调用 @classmethod def from_file(cls, f): return cls(f.read(cls.struct_size)) class Point(Structure_v3): _fields_ = [ ('