You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用struct.unpack解析GWI二进制文件头结构体GWI_file_header_struct

结构体转struct.unpack逻辑校验与后续数据解析方案

现有实现逻辑合理性说明

你已经可以正确读取头长度、字节序、通道名称,说明头解析的核心逻辑符合文件格式要求,现有逻辑是正确的,核心对齐规则如下:

  • 第一步读取前4字节获取单个头的字节长度,该逻辑匹配文件定义。你可以直接通过这4字节的解析结果确认全局字节序:如果用小端模式struct.unpack('<I', 前4字节)[0]得到516,说明整个文件是小端存储;如果用大端模式得到516则是大端存储,无需硬编码字节序。
  • 读取第一个头的channelsPerFile字段获取总通道数N,再循环读取N-1个剩余头的逻辑是正确的,只要每个头的长度都和第一个头的长度一致,就不会出现偏移错误。

GWI_file_header_struct转struct格式串的通用规则

你可以对照INET_INT.H头文件中的结构体定义,按以下规则匹配struct格式符,格式串开头加字节序前缀:小端加<,大端加>,本地字节序加=:

  • char/unsigned char:对应B(无符号)/b(有符号),占1字节
  • short/unsigned short:对应H(无符号)/h(有符号),占2字节
  • int/unsigned int:对应I(无符号)/i(有符号),占4字节
  • float:对应f,占4字节
  • char arr[N]:对应{N}s,例如char channelName[16]对应16s,读取后用.strip(b'\x00').decode()转为字符串
    注意结构体的内存对齐规则:如果凑出来的格式串总长度不等于你读取到的单个头长度,需要在对应位置加x作为填充字节,例如两个int字段之间有2字节对齐填充,就加2x跳过这2字节。

举个参考示例,假设头文件结构体定义如下:

typedef struct {
    uint32_t headerLen;
    uint32_t channelsPerFile;
    char channelName[16];
    float sampleRate;
    // 其余字段总长度为488字节
} GWI_file_header_struct;

对应的小端模式格式串为:<I I 16s f 488x,总长度为4+4+16+4+488=516字节,和单个头长度匹配。

后续交错32位浮点数据解析方案

读完N个头后,文件偏移位置就是数据区起始位置,按以下逻辑处理:

  1. 计算数据区总字节数:文件总大小减去头数组总长度(N * 单个头长度),每个采样点为4字节float,总采样点数 = 数据区总字节数 // 4
  2. 交错存储规则为[通道1第1个点, 通道2第1个点, ..., 通道N第1个点, 通道1第2个点, 通道2第2个点...],按该规则拆分数据即可
  3. 参考实现代码:
import struct
import os

# 替换为你确认的字节序前缀、头格式串
endian = '<'
header_format = f"{endian}I I 16s f 488x"
single_header_len = struct.calcsize(header_format)

file_path = "你的二进制文件路径"
file_size = os.path.getsize(file_path)

with open(file_path, 'rb') as f:
    # 读取所有头结构体
    headers = []
    # 读第一个头获取总通道数
    first_header = struct.unpack(header_format, f.read(single_header_len))
    # 替换为channelsPerFile字段在结构体中的实际索引
    channel_count = first_header[1]
    headers.append(first_header)
    # 读取剩余的头
    for _ in range(channel_count - 1):
        headers.append(struct.unpack(header_format, f.read(single_header_len)))
    
    # 读取并解析数据区
    data_bytes = f.read()
    total_sample_count = len(data_bytes) // 4
    data_format = f"{endian}{total_sample_count}f"
    all_samples = struct.unpack(data_format, data_bytes)
    
    # 按通道拆分数据
    channel_data = [[] for _ in range(channel_count)]
    for idx, sample in enumerate(all_samples):
        channel_idx = idx % channel_count
        channel_data[channel_idx].append(sample)
  • 如果文件过大不想一次性读入内存,可以按块读取,每次读取通道数 * 4 * 单块采样数的字节,解析后拆分到对应通道即可。

内容的提问来源于stack exchange,提问作者waterab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 07:57:04