无需X++ Conpeek,如何解析Container类型十六进制数据并转CSV?
解析Dynamics Axapta Container类型的十六进制字符串格式
Dynamics Axapta的Container类型是一种动态集合类型,其序列化后的二进制数据被转成十六进制字符串存储在数据库中。要在通用语言中解析这类数据,需先明确它的二进制结构规则,再对应处理十六进制转码后的字节流:
核心格式规则(二进制层面)
Container的序列化结构采用小端字节序,整体由「元素数量头部」+「逐个元素的类型+内容」组成:
- 头部:固定4字节,以小端整数表示容器内的元素总数量
- 单个元素结构:
- 1字节的类型标记(Type ID),常见标记对应类型:
0x01: 整数(Integer,32位小端整数)0x02: 字符串(String,UTF-16LE编码)0x03: 浮点数(Real,8字节双精度小端浮点数)0x04: 嵌套Container(结构与顶级容器完全一致)0x05: 日期(Date,32位小端整数,存储自1900-01-01起的天数)0x06: 枚举(Enum,32位小端整数,对应枚举值)0x07: 布尔值(Boolean,1字节,0为假、1为真)
- 对应类型的内容数据:
- 整数/日期/枚举:直接读取4字节转小端整数
- 字符串:先读4字节小端整数得到字符数,再读取
字符数×2字节转UTF-16LE字符串 - 浮点数:读取8字节转小端双精度浮点数
- 嵌套Container:递归执行解析逻辑
- 1字节的类型标记(Type ID),常见标记对应类型:
通用语言解析步骤(以Python为例)
- 十六进制转二进制:将存储的十六进制字符串转换为字节数组
hex_str = "00000001010000000A" # 示例:包含1个整数10的容器 byte_data = bytes.fromhex(hex_str) - 解析元素数量:读取前4字节,转小端整数得到元素总数
import struct count = struct.unpack("<I", byte_data[:4])[0] offset = 4 - 循环解析每个元素:根据类型标记读取对应内容,更新偏移量
elements = [] for _ in range(count): type_id = byte_data[offset] offset += 1 if type_id == 0x01: # 解析整数 val = struct.unpack("<i", byte_data[offset:offset+4])[0] offset +=4 elements.append(val) elif type_id == 0x02: # 解析字符串 str_len = struct.unpack("<I", byte_data[offset:offset+4])[0] offset +=4 str_bytes = byte_data[offset:offset+str_len*2] offset += str_len*2 val = str_bytes.decode("utf-16le") elements.append(val) # 其他类型可参照上述逻辑补充 - 导出为CSV:将解析后的元素列表(或嵌套结构扁平化后)写入CSV文件
import csv with open("output.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(elements) # 单条容器数据 # 若有多条数据,可循环writerow写入
注意事项
- 全程必须使用小端字节序解析,否则数值会完全错误
- 字符串解析必须用UTF-16LE编码,误用UTF-8会导致乱码
- 嵌套Container需要递归解析,避免遗漏内部数据
- 空容器的头部4字节为
00000000(十六进制),无后续元素
内容的提问来源于stack exchange,提问作者Michael.C
相关产品推荐
相关产品推荐

