欢迎访问宙启技术站
智能推送

深入理解Python中的struct模块:二进制数据处理的进阶指南

发布时间:2024-01-07 17:58:44

在Python中,struct模块提供了一种处理二进制数据的方式。它允许我们将二进制数据按照特定的格式解析和打包,便于进行数据的读取、写入和转换。本文将深入介绍Python中的struct模块,并提供一些使用例子。

struct模块的主要功能是将Python值和C结构体进行相互转换。它用于处理二进制数据,例如网络消息、二进制文件等。在使用struct模块之前,我们需要先了解一些基本的数据类型和格式化代码。

在struct模块中,常用的数据类型包括整数、浮点数和字符串。其中,整数可以分为有符号和无符号两种类型,浮点数可以分为单精度和双精度两种类型。

格式化代码用于指定数据在打包和解析过程中的格式。可以使用的格式化代码包括:

- 整数类型:

- 'b':有符号字节型(1字节)

- 'B':无符号字节型(1字节)

- 'h':有符号短整型(2字节)

- 'H':无符号短整型(2字节)

- 'i':有符号整型(4字节)

- 'I':无符号整型(4字节)

- 'l':有符号长整型(4字节)

- 'L':无符号长整型(4字节)

- 'q':有符号长长整型(8字节)

- 'Q':无符号长长整型(8字节)

- 浮点数类型:

- 'f':单精度浮点型(4字节)

- 'd':双精度浮点型(8字节)

- 字符串类型:

- 's':定长字符串

- 'p':定长字符串(代表pascal字符串)

- 'z':变长字符串(以空字符结尾)

接下来,我们将介绍一些常用的struct模块函数。

1. struct.pack(format, v1, v2, ...):将参数按照给定的格式format进行打包,返回打包后的二进制数据。例如,我们可以使用下面的代码将两个整数和一个浮点数打包成二进制数据。

import struct

data = struct.pack('iif', 1, 2, 3.14)
print(data)  # b'\x01\x00\x00\x00\x02\x00\x00\x00\xd0K\x0f@'

2. struct.unpack(format, data):按照给定的格式format从二进制数据中解析值,并以元组的形式返回。例如,我们可以使用下面的代码解析上面打包的二进制数据。

import struct

data = b'\x01\x00\x00\x00\x02\x00\x00\x00\xd0K\x0f@'
values = struct.unpack('iif', data)
print(values)  # (1, 2, 3.140000104904175)

3. struct.calcsize(format):计算给定格式的字节数。例如,我们可以使用下面的代码计算上面打包的二进制数据的字节数。

import struct

size = struct.calcsize('iif')
print(size)  # 12

除了上述函数外,struct模块还提供了一些其他的函数,例如:

- struct.iter_unpack(format, data):按照给定的格式从二进制数据中迭代解析值,并以元组的形式返回。

- struct.pack_into(format, buffer, offset, v1, v2, ...):将参数按照给定的格式format打包到缓冲区buffer中的指定位置。

- struct.unpack_from(format, buffer, offset):按照给定的格式format从缓冲区buffer的指定位置解析值,并以元组的形式返回。

下面我们通过一个具体的例子来演示struct模块的使用。

假设我们有一个二进制文件,其中每条记录都由一个用户名(定长字符串)和一个年龄(无符号整型)组成。我们想要读取这些记录,并将用户名和年龄打印出来。

import struct

with open('data.bin', 'rb') as f:
    while True:
        record = f.read(12)  # 每条记录占用12字节(8字节用户名 + 4字节年龄)
        if not record:
            break
        
        username, age = struct.unpack('8sI', record)
        print(f"Username: {username.decode()}, Age: {age}")

在上面的例子中,我们使用'8sI'格式解析每条记录。其中,'8s'表示定长8字节字符串,'I'表示无符号整型。我们使用decode()函数将字节型的用户名转换为字符串。

通过上述例子,我们可以看到struct模块在处理二进制数据时的强大功能。通过合理地选择格式化代码,我们可以轻松地解析和打包各种类型的二进制数据。无论是读取网络数据还是处理二进制文件,struct模块都是一个非常实用的工具。