struct —— 二进制数据结构

原文地址:https://pymotw.com/3/struct/

目的:在字符串和二进制数据之间转换。

struct模块包括用于在字节字符串和Python原生数据类型(比如数字和字符串)之间转换的函数。

函数 vs Struct类

一组模块级别的函数和Struct类都可以用于结构化值。格式说明符从它的字符串格式转换为编译后的描述,类似于处理正则表达式的方式。转换需要一些资源,所以创建一个Struct实例并在实例上调用方法,比使用模块级别的函数更高效。以下所有示例都使用Struct类。

打包和拆包

struct使用由字符串组成的格式说明符表示数据类型和可选的计数与字节顺序指示符,支持将数据打包为字符串,以及从字符串拆包数据。支持的完整格式说明符列表请参考标准库文档。

这个示例中,说明符需要一个整数或长整数值,一个双字节字符串和一个浮点数。格式说明符中的空格用于分隔类型指示符,在编译格式时会被忽略。

# struct_pack.py

import struct
import binascii

values = (1, 'ab'.encode('utf-8'), 2.7)
s = struct.Struct('I 2s f')
packed_data = s.pack(*values)

print('Original values:', values)
print('Format String  :', s.format)
print('Uses           :', s.size, 'bytes')
print('Packed Value   :', binascii.hexlify(packed_data))

因为有些字符为空,为了使用binascii.hexlify()打印,该示例把打包的值转换为十六进制字节序列。

$ python3 struct_pack.py

Original values: (1, b'ab', 2.7)
Format string  : b'I 2s f'
Uses           : 12 bytes
Packed Value   : b'0100000061620000cdcc2c40'

使用unpack()从它打包表示中提取数据。

# struct_unpack.py

import struct
import binascii

packed_data = binascii.unhexlify(b'0100000061620000cdcc2c40')

s = struct.Struct('I 2s f')
unpacked_data = s.unpack(packed_data)
print('Unpacked Values:', unpacked_data)

把打包的数据传递给unpack(),会返回基本相同的值(注意浮点值的差异)。

$ python3 struct_unpack.py

Unpacked Values: (1, b'ab', 2.700000047683716)

字节顺序

默认情况下,值使用本机C库的字节顺序编码。通过在格式化字符串中提供明确的字节顺序指令,可以很容易地覆盖该选择。

# struct_endianness.py

import struct
import binascii

values = (1, 'ab'.encode('utf-8'), 2.7)
print('Original values:', values)

endianness = [
    ('@', 'native, native'),
    ('=', 'native, standard'),
    ('<', 'little-endian'),
    ('>', 'big-endian'),
    ('!', 'network'),
]

for code, name in endianness:
    s = struct.Struct(code + ' I 2s f')
    packed_data = s.pack(*values)
    print()
    print('Format string   :', s.format, 'for', name)
    print('Uses            :', s.size, 'bytes')
    print('Pakced Value    :', binascii.hexlify(packed_data))
    print('Unpacked Value  :', s.unpack(packed_data))

下表列出了Struct使用字节顺序说明符。

代码意义
@Native order
=Native standard
<little-endian
>big-endian
!Network order
$ python3 struct_endianness.py

Original values: (1, b'ab', 2.7)

Format string  : b'@ I 2s f' for native, native
Uses           : 12 bytes
Packed Value   : b'0100000061620000cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : b'= I 2s f' for native, standard
Uses           : 10 bytes
Packed Value   : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : b'< I 2s f' for little-endian
Uses           : 10 bytes
Packed Value   : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : b'> I 2s f' for big-endian
Uses           : 10 bytes
Packed Value   : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : b'! I 2s f' for network
Uses           : 10 bytes
Packed Value   : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)

缓冲区

使用二进制打包数据通常用于性能敏感情况,或者把数据传出或传入扩展模块。这些情况下,通过避免为每个被打包的结构分配新缓冲区的开销来进行优化。pack_into()unpack_from()函数支持直接写入预分配的缓冲区。

# struct_buffers.py

import array
import binascii
import ctypes
import struct

s = struct.Struct('I 2s f')
values = (1, 'ab'.encode('utf-8'), 2.7)
print('Original:', values)

print()
print('ctypes string buffer')

b = ctypes.create_string_buffer(s.size)
print('Befor   :', binascii.hexlify(b.raw))
s.pack_into(b, 0, *values)
print('After   :', binascii.hexlify(b.raw))
print('Unpacked:', s.unpack_from(b, 0))

print()
print('array')

a = array.array('b', b'\0' * s.size)
print('Befor   :', binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('After   :', binascii.hexlify(a))
print('Unpacked:', s.unpack_from(a, 0))

Structsize属性告诉我们需要多大的缓冲区。

$ python3 struct_buffers.py

Original: (1, b'ab', 2.7)

ctypes string buffer
Before  : b'000000000000000000000000'
After   : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)

array
Before  : b'000000000000000000000000'
After   : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)

参考

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值