有人可以解释 Python 结构解包吗?
Can someone explain Python struct unpacking?
我有一个由 C 结构组成的二进制文件,我想在 Python 中解析它。我知道二进制文件的确切格式和布局,但我对如何使用 Python 结构解包来读取此数据感到困惑。
我是否必须根据结构的成员一次遍历整个二进制文件解包一定数量的字节?
C 文件格式:
typedef struct {
int data1;
int data2;
int data4;
} datanums;
typedef struct {
datanums numbers;
char *name;
} personal_data;
假设二进制文件有 personal_data 个重复的结构。
您一次可以打开几个。让我们从这个例子开始:
In [44]: a = struct.pack("iiii", 1, 2, 3, 4)
In [45]: a
Out[45]: '\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
如果您使用的是字符串,您可以只使用它的一个子集,或者使用 unpack_from:
In [49]: struct.unpack("ii",a[0:8])
Out[49]: (1, 2)
In [55]: struct.unpack_from("ii",a,0)
Out[55]: (1, 2)
In [56]: struct.unpack_from("ii",a,4)
Out[56]: (2, 3)
如果您正在使用缓冲区,则需要使用 unpack_from
。
假设布局是一个静态的二进制结构,可以用一个简单的struct
模式来描述,而文件就是那个结构,一遍又一遍地重复,那么是的,"traverse the whole binary unpacking a certain number of bytes at a time"就是你会做什么。
例如:
record = struct.Struct('>HB10cL')
with open('myfile.bin', 'rb') as f:
while True:
buf = f.read(record.size)
if not buf:
break
yield record.unpack(buf)
如果您担心一次只读取 17 个字节的效率,并且想通过一次缓冲 8K 或其他方式来解决这个问题……好吧,首先要确保这是一个值得优化的实际问题;然后,如果是,循环 unpack_from
而不是 unpack
。像这样的东西(未经测试,我头脑中的代码):
buf, offset = b'', 0
with open('myfile.bin', 'rb') as f:
if len(buf) < record.size:
buf, offset = buf[offset:] + f.read(8192), 0
if not buf:
break
yield record.unpack_from(buf, offset)
offset += record.size
或者,甚至更简单,只要文件对于您的 vmsize 来说不是太大,只需 mmap
整个文件和 unpack_from
mmap
本身:
with open('myfile.bin', 'rb') as f:
with mmap.mmap(f, 0, access=mmap.ACCESS_READ) as m:
for offset in range(0, m.size(), record.size):
yield record.unpack_from(m, offset)
我有一个由 C 结构组成的二进制文件,我想在 Python 中解析它。我知道二进制文件的确切格式和布局,但我对如何使用 Python 结构解包来读取此数据感到困惑。
我是否必须根据结构的成员一次遍历整个二进制文件解包一定数量的字节?
C 文件格式:
typedef struct {
int data1;
int data2;
int data4;
} datanums;
typedef struct {
datanums numbers;
char *name;
} personal_data;
假设二进制文件有 personal_data 个重复的结构。
您一次可以打开几个。让我们从这个例子开始:
In [44]: a = struct.pack("iiii", 1, 2, 3, 4)
In [45]: a
Out[45]: '\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
如果您使用的是字符串,您可以只使用它的一个子集,或者使用 unpack_from:
In [49]: struct.unpack("ii",a[0:8])
Out[49]: (1, 2)
In [55]: struct.unpack_from("ii",a,0)
Out[55]: (1, 2)
In [56]: struct.unpack_from("ii",a,4)
Out[56]: (2, 3)
如果您正在使用缓冲区,则需要使用 unpack_from
。
假设布局是一个静态的二进制结构,可以用一个简单的struct
模式来描述,而文件就是那个结构,一遍又一遍地重复,那么是的,"traverse the whole binary unpacking a certain number of bytes at a time"就是你会做什么。
例如:
record = struct.Struct('>HB10cL')
with open('myfile.bin', 'rb') as f:
while True:
buf = f.read(record.size)
if not buf:
break
yield record.unpack(buf)
如果您担心一次只读取 17 个字节的效率,并且想通过一次缓冲 8K 或其他方式来解决这个问题……好吧,首先要确保这是一个值得优化的实际问题;然后,如果是,循环 unpack_from
而不是 unpack
。像这样的东西(未经测试,我头脑中的代码):
buf, offset = b'', 0
with open('myfile.bin', 'rb') as f:
if len(buf) < record.size:
buf, offset = buf[offset:] + f.read(8192), 0
if not buf:
break
yield record.unpack_from(buf, offset)
offset += record.size
或者,甚至更简单,只要文件对于您的 vmsize 来说不是太大,只需 mmap
整个文件和 unpack_from
mmap
本身:
with open('myfile.bin', 'rb') as f:
with mmap.mmap(f, 0, access=mmap.ACCESS_READ) as m:
for offset in range(0, m.size(), record.size):
yield record.unpack_from(m, offset)