[Python] Python struct模块学习

本文介绍了Python的struct模块,用于处理二进制数据。详细讲解了struct.pack、unpack方法及格式规范字符串,包括字节顺序、大小和对齐。通过示例展示了如何将数据打包写入二进制文件以及从文件中读取解包数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

struct模块

struct模块用于将Python中的bytes类型对象和C语言中的struct进行转换,一般用于处理存储在文件或网络中的二进制文件,使用struct模块时需要指定一个格式规范,来对字节大小、顺序、对齐等进行约束。

常用方法:

struct.pack(fmt,v1,v2,…):以一个struct格式化字符串以及一个或多个值为参数,返回一个bytes对象,其中存放的是按照该格式规范表示的所有的这些参数值。
struct.unpack(fmt,buffer):以一个格式规范和一个bytes/bytearray对象为参数(缓冲区),返回一个元组,缓冲区的大小必须和格式规范fmt保持一致。
struct.calcsize(fmt):返回格式规范fmt的大小,和pack()打包后的bytes对象大小一致。

格式规范字符串

格式字符串是在打包和解包数据时用于指定预期布局的机制,它们由格式字符构成,它指定了打包/解压缩数据的类型。另外,还有用于控制字节顺序,大小和对齐的特殊字符。指定的一些值如下,下表来自于python官方文档,更多细节请参考Python官方文档struct模块

FormatC TypePython typeStandard sizeNotes
xpad byteno value
ccharbytes of length11
bsigned charinteger1(1),(3)
Bunsigned charinteger1(3)
?_Boolbool1(1)
hshortinteger2(3)
Hunsigned shortinteger2(3)
iintinteger4(3)
Iunsignedintinteger4
llonginteger4(3)
Lunsigned longinteger4(3)
qlong longinteger8(2), (3)
Qunsigned longlong8(2), (3)
nssize_tinteger(4)
Nsize_t integerinteger(4)
e(7)float2(5)
ffloatfloat4(5)
ddoublefloat8(5)
schar[]bytes
pchar[]bytes
Pvoid *integer(6)

如:

# 从上表中看出,h在C中表示short,python中表示integer,占2个字节大小,因此返回的bytes对象中包含2*3个字节
>>> struct.pack("hhh",1,2,3) 
b'\x01\x00\x02\x00\x03\x00'
>>> 
# l在C中表示long型,在python中表示integer,占4个字节,因此返回的不要bytes对象中1,2占分别4个字节,3占2字节
>>> struct.pack("llh",1,2,3)
b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00'
>>> 

在上表中,c表示一个byte对象,s通常用于对str进行格式规范,10c表示10个byte对象,10s表示10个byte组成的str,如:

>>> struct.pack("4sl","just".encode("utf-8"),3)
b'just\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'
>>> 
>>> struct.pack("4cl","j".encode("utf8"),"j".encode("utf8"),"j".encode("utf8"),"j".encode("utf8"),3)
b'jjjj\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'
>>> 
字节顺序(ByteOrder)、大小(Size)和对齐(alignment)

默认情况下,C语言中的数据类型使用本地格式和顺序表示,并且在必要时会跳过填充字节保持对齐,因此,在将Python和C之间进行转换时,可以使用下表中的字符作为格式规范可以指示这三个属性:

CharacterByte orderSizeAlignment
@nativenativenative
=nativestandardnone
<little-endianstandardnone
>big-endianstandardnone
!network(= big-endian)standard

little-endian和big-endian称为字节序,其中广泛使用的是little-endian,如果格式规范中没有指定字节序,则使用平台本身字节序。如:

>>> struct.pack("<llh",1,2,3)
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00'
>>> struct.pack(">llh",1,2,3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03'
>>> 
# 使用平台本地字节顺序、size大小、对齐方式
>>> struct.pack("@llh",1,2,3)
b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00'
>>> 

示例

下面例子展示了如何通过struct模块将对象存储到二进制文件中,以及在二进制文件中读取对象:

import struct
import sys
import os


class Student:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        assert isinstance(age, int), "age must be integer"
        self.__age = age

    #  将对象写入二进制文件中
    def export_binary(self, filename):

        # 对于str类型,如果不进行该步骤,则会出现export error:argument for 's' must be a bytes object
        def packing_string(name):
            return name.encode("utf8")

        fh = None
        try:
            # 指定文件操作为二进制写操作
            fh = open(filename, "wb")
            # self.name为str类型,使用struct.pack8()时,必须将str类型转换为bytes类型,因此使用一个局部方法进行转换
            data = packing_string(self.name)
            data_len = len(data)
            fh.write(struct.pack("<{0}si".format(data_len), data, self.age))
            return True
        except Exception as err:
            print("{0}:export error:{1}".format(os.path.basename(sys.argv[0]), err))
            return False
        finally:
            if fh is not None:
                fh.close()

    def import_binary(self, filename):
        fh = None
        try:
            # 二进制文件读操作
            fh = open(filename, "rb")
            if fh is not None:
                s = fh.read()
                ss = struct.unpack("<{0}si".format(len(s)-4), s)
                print(ss)  # (b'zhangsan', 21)
                return True
        except Exception as err:
            print("{0}:export error:{1}".format(os.path.basename(sys.argv[0]), err))
            return False
        finally:
            if fh is not None:
                fh.close()


if __name__ == "__main__":
    s1 = Student("zhangsan", 21)
    s2 = Student("Lisi", 23)
    s1.export_binary("s1.bin")
    s1.import_binary("s1.bin")

参考文档:https://docs.python.org/3/library/struct.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值