struct模块

作者: lakerszhy | 来源:发表于2017-04-17 17:52 被阅读246次

    该模块在Python值和表示为Python bytes对象的C结缓冲区构体之间进行转换。可用于处理存储在文件中或者来自网络连接,以及其它来源的二进制数据。它使用格式化字符串,作为C结构体布局的简洁描述,以及从Python值,或者到Python值的预期转换。

    注意:默认情况下,封装给定的C结构体的结构包括填充字节,以便为涉及的C类型保持正确的对齐;类似地,解包时会考虑对齐。选择此行为使得被封装的结构体的字节完全对应于C结构体在内存中的布局。要处理平台无关的数据格式,或者忽略隐式的填充字节,可以使用standard大小和对齐,代替native大小和对齐,查看字节顺序,大小和对齐了解详情。

    有几个struct函数(和Struct的方法)接收一个buffer参数。它引用实现了Buffer协议的对象,并提供一个可读,或可读写的缓存。用于该目的的最常见的类型是bytesbytearray,但是可以视为字节数组的许多其它类型实现了Buffer协议,因此它们可以读和填充,而不需要额外的从bytes对象复制。

    1 函数和异常

    该模块定义了以下异常和函数:

    1.1 异常 struct.error

    在各种场合下抛出异常;参数是描述错误的字符串。

    1.2 struct.pack(fmt, v1, v2, ...)

    根据格式化字符串fmt封装,返回一个包括v1v2等值的字节对象。参数必须与格式化所需的值完全匹配。

    1.3 struct.pack_into(ftm, buffer, offset, v1, v2, ...)

    根据格式化字符串fmt,封装v1v2等值,并从位置offset开始,将封装的字节写入可写缓冲区buffer中。注意,offset是必需的参数。

    1.4 struct.unpack(fmt, buffer)

    根据格式化字符串fmt,从缓冲区buffer(假设由pack(fmt, ...)封装)中解包。即使结果只包含一项,也是一个元组。缓冲区的大小(以字节为单位)必需与格式所需的大小匹配,比如calcsize()所得的结果。

    1.5 struct.unpack_from(fmt, buffer, offset=0)

    根据格式化字符串fmt,从位置offset开始解包。即使结果只包含一项,也是一个元组。缓冲区的大小(以字节为单位)减去offset,至少是格式化所需的大小,比如calcsize()所得的结果。

    1.5 struct.iter_unpack(fmt, buffer)

    版本3.4中新增。

    根据格式化字符串fmt,从缓冲区buffer中迭代解包。该函数返回一个iterator,它将从缓冲区中读取大小相等的块,直到所有内容被耗尽。缓冲区的大小(以字节为单位)必须是格式化所需大小的倍数,比如calcsize()所得的结果。

    每次迭代yield一个由格式化字符串指定的元组。

    1.6 struct.calcsize(fmt)

    返回对应于格式化字符串fmt的结构体(以及由pack(fmt, ...)生成的字节对象)的大小。

    2 格式化字符串

    封装和解包数据时,格式化字符串是用于指定预期布局的机制。它们由Format Characters构成,指定封装和解包的数据类型。此外,还有一些特殊字符控制字节顺序,大小和对齐。

    2.1 字节顺序,大小和对齐

    默认情况下,C语言类型以机器的本机格式和字节顺序表示,如果需要(根据C编译器使用的规则),跳过填充字节,以便正确对齐。

    或者根据下表,格式化字符串的第一个字符用于表明封装数据的字节顺序,大小和对齐:

    字符 字节顺序 大小 对齐
    @ 本机 本机 本机
    = 本机 标准
    < 小端 标准
    > 大端 标准
    ! 网络(等于大端) 标准

    如果第一个字符不是其中之一,则假定为“@”。

    本地字节顺序是大端或小端,这取决于主机系统。例如,Intel x86和AMD64(x86-64)是小端字节序;摩托罗拉68000和PowerPC G5是大端字节序;ARM和Intel Itanium可切换字节顺序(双字节顺序)。使用sys.byteorder检查系统的字节顺序。

    使用C编译器的sizeof表达式确定本机大小和对齐。这总是与本机字节顺序结合。

    标准大小仅取决于格式化字符;参考格式化字符中的表格。

    注意“@”和“=”之间的区别:都使用本机字节顺序;但后者的大小和对齐是标准的。

    “!”形式用于忘记网络字节顺序是大端还是小端的情况。

    没有办法表示非本地字节顺序(强制字节交换);使用适当的“<”或“>”。

    注意:

    1. 填充仅在连续的结构体成员之间自动添加。在编码的结构体的开头或结尾不填充。
    2. 使用非本地大小和对齐时,不添加填充,比如“<”,“>”,“=”和“!”。
    3. 要将结构体结尾与特殊类型的对齐要求对齐,使用重复计数为0的该类型的代码结束格式。

    2.2 格式化字符

    版本3.1中修改:在3.0中,有些整数格式封装了超出范围的值,并抛出DeprecationWarning代替struct.error

    版本3.2中修改:新增为非整数使用__index__()方法。

    版本3.3中修改:添加“n”和“N”格式。

    版本3.6中修改:添加“e”格式。

    格式化字符有以下含义:C和Python值之间的转换应该明确指定类型。“标准大小”列表示,使用标准大小时,被封装值的字节大小;也就是格式化字符串以“<”,“>”,“!”或“=”开始时。当使用本机大小,被封装值的大小是平台相关的。

    格式 C类型 Python类型 标准大小 提示
    x 填充字节 没有值
    c char 长度为1的字节 1
    b signed char integer 1 1,3
    B unsigned char integer 1 3
    ? _Bool bool 1 1
    h short integer 2 3
    H unsigned short integer 2 3
    i int integer 4 3
    I unsigned int integer 4 3
    l long integer 4 3
    L unsigned long integer 4 3
    q long long integer 8 2,3
    Q unsigned long long integer 8 2,3
    n ssize_t integer 4
    N size_t integet 4
    e 7 float 2 5
    f float float 4 5
    d double float 8 5
    s char[] bytes
    p char[] bytes
    P void * integer 6

    提示:

    1. “?”转换码对应的_Bool类型由C99定义。如果该类型不可用,使用char模拟。在标准模式下,它总是由一个字节表示。
    2. 只有C编译器支持long long类型,或者Windows上的__int64时,“q”和“Q”转换码才在本机模式下可用。在标准模式下它们总是可用。
    3. 使用图任何整数转换码封装一个非整数时,如果非整数有__index__()方法,则在封装前会调用该方法把参数转换为整数。
    4. “n”和“N”转换只在本机大小中可用(选择默认或“@”字节顺序)。对于标准大小,可用使用适合应用程序的其它整数格式。
    5. 对于“f”,“d”和“e”转换码,封装分别表示使用IEEE 754的binary32,binary64或binary16格式,而不管平台使用的浮点数格式。
    6. “P”只在本机字节顺序可用(选择默认或“@”字节顺序)。“=”根据主机系统选择使用小端或大端顺序。struct模块不会解释为本机顺序,因此“P”格式不可用。
    7. IEEE 754标准的2008版本中,引入了IEEE 754 binary16半精度。它有一个符号位,5位指数和11位精度(其中10位存储),全精度可用表示大约6.1e-056.1e-05。C编译器没有广泛支持该类型;在典型的机器中,unsigned short可用于存储,但不适合数据运算。

    可以在格式化字符之前使用整数表示重复次数。例如,“4h”完全等价于“hhhh”。

    尽管次数和它的格式不可能包含空格,还是会忽略格式化字符之前的空格。

    对于“s”格式化字符,次数表示字节的长度,而不是其它格式化字符的重复次数;例如,“10s”表示单个10个字节的字符串,“10c”表示10个字符。如果没有指定次数,默认为1。对于封装,字符串被截断,或者用空字节填充,让其正确适应。对于解包,生成的字节对象总是指定的字节数。对于特殊情况,“0s”表示单个空字符串(“0c”表示0个字符)。

    使用其中一个整数格式(“b”,“B”,“h”,“H”,“i”,“I”,“l”,“L”,“q”,“Q”)封装值x的时候,如果x超出格式的有效返回,会抛出struct.error异常。

    格式化字符“p”编码一个Pascal string,表示一个short可变长度的字符串存储在固定字节数中,其长度由次数指定。第一个字节存储字符串的长度,或者255,取两者中的较小者。接着是字节的字符串。如果传递到pack()中的字符串太长(长于次数减1),则只存储前count-1个字节。如果字符串比count-1短,则使用空字节填充,以便使用所有字节。注意,对应unpack(),“p”格式化字符消耗count个字节,但返回的字符串永远不会超过255个字节。

    对于“?”格式化字符,返回值是TrueFalse。封装时,使用参数对象的真值。在本机或标准bool表示中,0或1会被封装,解包时任何非0值是True

    2.3 示例

    注意:所有示例假设本机字节顺序和大小,以及大端机器对齐。

    封装/解包三个整数的基本示例:

    >>> from struct import *
    >>> pack('hhl', 1, 2, 3)
    b'\x00\x01\x00\x02\x00\x00\x00\x03'
    >>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
    (1, 2, 3)
    >>> calcsize('hhl')
    8
    

    解包的字段可以通过分配给变量,或者将结果包装在命名元组中来命名:

    >>> record = b'raymond  \x32\x12\x08\x01\x08'
    >>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
    
    >>> from collections import namedtuple
    >>> Student = namedtuple('Student', name serialnum school, gradelevel')
    >>> Student._make(unpack('<10sHHb', record))
    Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)
    

    格式化字符的顺序可能会对大小有影响,因为满足对齐需求的填充是不同的:

    >>> pack('ci', b'*', 0x12131415)
    b'*\x00\x00\x00\x12\x13\x14\x15'
    >>> pack('ic', 0x12131415, b'*')
    b'\x12\x13\x14\x15*'
    >>> calcsize('ci')
    8
    >>> calcsize('ic')
    5
    

    下面的“11h01”格式,在结尾指定了两个填充字节,假设long在4字节边界对齐:

    >>> pack('11h01', 1, 2, 3)
    b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
    

    这只在本机大小和对齐有效时才其作用;标准大小和对齐不强制任何对齐。

    3 类

    struct模块还定义了以下类型:

    3.1 类struct.Struct(format)

    返回一个新的Struct对象,更具格式化字符串format写入和读取二进制数据。创建一个Struct对象,并调用它的方法,比用同样格式调用struct函数更高效,因为格式化字符串只需要编译一次。

    编译的Struct对象支持以下方法和属性:

    3.1.1 pack(v1, v2, ...)

    完全等同于pack()函数,使用编译后的格式。(len(result)将会等于size

    3.1.2 pack_into(buffer, offset, v1, v2, ...)

    完全等同于pack_into()函数,使用编译后的格式。

    3.1.3 unpack(buffer)

    完全等同于unpack()函数,使用编译后的格式。缓冲区的大小(以字节为单位)必须等于size

    3.1.4 unpack_from(buffer, offset=0)

    完全等同于unpack_from()函数,使用编译后的格式。缓冲区的大小减去offset(以字节为单位)必须至少为size

    3.1.5 iter_unpack(buffer)

    版本3.4中新增。

    完全等同于iter_unpack()函数,使用编译后的格式。缓冲区的大小(以字节为单位)必须是size的倍数。

    3.1.6 format

    构造该Struct对象的格式化字符串。

    3.1.7 size

    对应于format的结构体(以及由pack(fmt, ...)生成的字节对象)的大小。

    相关文章

      网友评论

        本文标题:struct模块

        本文链接:https://www.haomeiwen.com/subject/seatzttx.html