如何使用Python从二进制文件解包字节数组?

如何使用Python从二进制文件解包字节数组?,python,python-3.x,Python,Python 3.x,我正在给自己上一个速成班,学习如何使用Python阅读二进制文件。我对这两个都不熟悉,所以请容忍我 文件格式的文档告诉我,前16个字节是GUID,进一步阅读会告诉我,此GUID的格式如下: typedef struct { unsigned long Data1; unsigned short Data2; unsigned short Data3; byte Data4[8]; } GUID, UUID, *PGUID; 我已经尽可能地让我们能够解包结构中的前三个条目

我正在给自己上一个速成班,学习如何使用Python阅读二进制文件。我对这两个都不熟悉,所以请容忍我

文件格式的文档告诉我,前16个字节是GUID,进一步阅读会告诉我,此GUID的格式如下:

typedef struct {
  unsigned long Data1;
  unsigned short Data2;
  unsigned short Data3;
  byte Data4[8];
} GUID, 
 UUID, 
 *PGUID;
我已经尽可能地让我们能够解包结构中的前三个条目,但我在#4上遇到了难题。我想这是一个8字节的数组,但我不知道如何解包

import struct

fp = open("./file.bin", mode='rb')

Data1 = struct.unpack('<L', fp.read(4)) # unsigned long, little-endian
Data2 = struct.unpack('<H', fp.read(2)) # unsigned short, little-endian 
Data3 = struct.unpack('<H', fp.read(2)) # unsigned short, little-endian
Data4 = struct.unpack('<s', bytearray(fp.read(8))) # byte array with 8 entries?

struct.error: unpack requires a bytes object of length 1
Python支持的。这样做:

import uuid

my_uuid = uuid.UUID(bytes_le=fp.read(16))

如果您想要一个8字节的字符串,则需要在其中输入数字
8

struct.unpack('<8s', bytearray(fp.read(8)))
字节
转换为
字节数组
除了生成可变副本外没有任何效果。解压缩它只会返回一个与开始时相同的
字节的副本。那么…为什么


实际上,
struct.unpack
返回一个
tuple
,它的一个值是您开始使用的相同
字节的副本,但是您可以使用:

Data4 = (fp.read(8),)
这就提出了一个问题,为什么首先需要四个单元素元组。你将无缘无故地到处做
Data1[0]
,等等。为什么不是这个

Data1, Data2, Data3, Data4 = struct.unpack('<LHH8s', fp.read(16))

但是请记住,Python的uuid使用的是4-2-2-1-1-6格式,而不是4-2-2-8格式。如果您确实需要这种格式,那么您需要转换它,这意味着无论是
struct
还是位旋转。(Microsoft的GUID使用了4-2-2-2-6格式,这两种格式都不一样,并且在本机endian中表示前3种格式,在big endian中表示后2种格式,因为它们喜欢使事情变得更简单……

如果将struct与bytearray结合使用,这两种格式是不同的。我不熟悉bytearray,但我很确定
struct.unpack()
不会接受由
bytearray返回的对象,因为它支持。@icktoofay谢谢!很高兴知道!另外,不需要
bytearray
(虽然不会有什么伤害)。@icktoofay:你说得对……但是也不需要整个
解包
。。谢谢你的评论。非常有帮助,我现在尝试阅读文件的其余部分:)
字节
是以大端顺序排列的;OP的数据(假设他得到了
struct
格式正确)是以little-endian表示的。因此,这里需要
字节,而不是
字节
。另外,值得注意的是Python的UUID是4-2-2-1-1-6,而不是4-2-2-8。因此,如果要获得4-2-2-8格式,必须手动转换
字段。
Data4 = (fp.read(8),)
Data1, Data2, Data3, Data4 = struct.unpack('<LHH8s', fp.read(16))
data = uuid.UUID(bytes_le=fp.read(16))