在 struct.unpack 格式字符串中间切换字节序

Quu*_*one 6 python struct endianness

我有一堆二进制数据(视频游戏保存文件的内容,因为它发生),其中一部分数据包含小端大端整数值。天真地,在没有阅读大量文档的情况下,我试图以这种方式打开它......

struct.unpack(
    '3sB<H<H<H<H4s<I<I32s>IbBbBbBbB12s20sBB4s',
    string_data
)
Run Code Online (Sandbox Code Playgroud)

...当然我收到了这个神秘的错误消息:

struct.error: bad char in struct format
Run Code Online (Sandbox Code Playgroud)

问题是struct.unpack格式字符串不希望单个字段被标记为字节序。此处实际正确的格式字符串类似于

struct.unpack(
    '<3sBHHHH4sII32sIbBbBbBbB12s20sBB4s',
    string_data
)
Run Code Online (Sandbox Code Playgroud)

除了这将翻转第三个I字段的字节序(将其解析为小端,当我真的想将其解析为大端时)。

我的问题有简单和/或“Pythonic”的解决方案吗?我已经想到了三种可能的解决方案,但没有一个是特别优雅的。如果没有更好的想法,我可能会选择第 3 条:

  1. 我可以提取一个子字符串并单独解析它:

    (my.f1, my.f2, ...) = struct.unpack('<3sBHHHH4sII32sIbBbBbBbB12s20sBB4s', string_data)
    my.f11 = struct.unpack('>I', string_data[56:60])
    
    Run Code Online (Sandbox Code Playgroud)
  2. 事后我可以翻转字段中的位

    (my.f1, my.f2, ...) = struct.unpack('<3sBHHHH4sII32sIbBbBbBbB12s20sBB4s', string_data)
    my.f11 = swap32(my.f11)
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我可以改变我的下游代码以期望这个字段以不同的方式表示——它实际上是一个位掩码,而不是一个算术整数,所以翻转我正在使用的所有位掩码不会太难;但是这些位掩码的 big-endian 版本比 little-endian 版本在助记方面更相关。

Cla*_*aas 0

聚会有点晚了,但我也遇到了同样的问题。我用自定义 numpy dtype 解决了这个问题,它允许混合具有不同字节顺序的元素(请参阅https://numpy.org/doc/stable/reference/ generated/numpy.dtype.html ):

t=np.dtype('>u4,<u4') # Compound type with two 4-byte unsigned int with different byte order
a=np.zeros(shape=1, dtype=t) # Create an array of length one with above type
a[0][0]=1 # Assign first uint
a[0][1]=1 # Assign second uint
bytes=a.tobytes() # bytes should be b'\x01\x00\x00\x00\x00\x00\x00\x01'
b=np.frombuffer(buf, dtype=t) # should yield array[(1,1)]
c=np.frombuffer(buf, dtype=np.uint32) # yields array([       1, 16777216]
Run Code Online (Sandbox Code Playgroud)