3

我正在给自己上一门使用 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

我对 Data4 做错了什么?(我正在使用 Python 3.2 顺便说一句)

Data1 到 3 都可以。如果我在它们上使用 hex(),我会得到我希望看到的正确数据(哇哦),我只是在这个字节数组的语法上失败了。

编辑:回答

我正在阅读 MS-DTYP 中定义的 GUID,这确定了它:

data = uuid.UUID(bytes_le=fp.read(16))
4

2 回答 2

11

如果你想要一个 8 字节的字符串,你需要把数字8放在那里:

struct.unpack('<8s', bytearray(fp.read(8)))

文档

格式字符前面可以有一个整数重复计数。例如,格式字符串“4h”的含义与“hhhh”完全相同。

对于 's' 格式字符,计数被解释为字节的长度,而不是像其他格式字符那样的重复计数;例如,'10s' 表示单个 10 字节字符串,而 '10c' 表示 10 个字符。如果未给出计数,则默认为 1。对于打包,字符串将被截断或用空字节填充以使其适合。对于解包,生成的字节对象始终具有完全指定的字节数。作为一种特殊情况,'0s' 表示单个空字符串(而 '0c' 表示 0 个字符)。


但是,我不确定您为什么首先要这样做。

fp.read(8)给你一个 8 字节的bytes对象。你想要一个 8 字节的bytes对象。所以,只需这样做:

Data4 = fp.read(8)

将 转换bytes为 abytearray除了制作可变副本之外没有任何作用。打开它只是给你一个bytes你开始时的副本。所以为什么?


好吧,实际上,struct.unpack返回tuple一个值是bytes你开始时的副本,但你可以这样做:

Data4 = (fp.read(8),)

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

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

当然,如果这是为了读取 UUID,使用“包含的电池”总是比尝试用镍和镉矿石制造自己的电池要好。正如 icktoofay 所说,只需使用该uuid模块:

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

但请记住,Pythonuuid使用 4-2-2-1-1-6 格式,而不是 4-2-2-8 格式。如果您确实需要该格式,则需要对其进行转换,这意味着struct无论如何都要进行处理。(Microsoft 的 GUID 使用 4-2-2-2-6 格式使事情变得更加有趣,这与两者都不相同,并以 native-endian 表示前 3 个,以 big-endian 表示后两个,因为它们喜欢让事情变得更容易......)

于 2013-05-12T21:42:20.837 回答
4

带有模块的Python 支持uuidUUID。做这样的事情:

import uuid

my_uuid = uuid.UUID(bytes_le=fp.read(16))
于 2013-05-12T21:37:27.417 回答