有的时候需要操作到字节层面,需要struct模块的支持
而内置函数memoryview提供了按字节的内存访问接口,好处是不会有内存拷贝,类似于c指针
一般与array.array bytearray 一起使用

1
2
3
4
5
6
7
8
9
10
11
12
# memoryview示例
a = 'aaaaaa'
ma = memoryview(a.encode()) #只能传入一个支持buffer protocol的object,原生支持的只有bytes和bytearray 返回一个memoryview
# 比如 mb = memoryview(b'aaaaa')
ma.readonly # 设为只读,不能修改
mm = ma.toreadonly() # mm是只读
mb = ma[:2] # mb = [97,97]
ma.tobytes() # 转成bytes b'aaaaa'
ma.tolist() # 转成list [97,97,97,97]

b = bytearray(b'asdf') # b'asdf'是一个bytes类型,bytearray和bytes不一样的地方在于,bytearray是可变的。
mb = memoryview(b)

struct中主要的三个函数pack() unpack() calcsize()
pack(fmt,v1,v2,...) 根据所给的fmt将v1,v2,…转换为一个bytes
unpack(fmt,bytes) 根据所给的fmt将bytes 解析,转为元组
calcsize(fmt) 根据所给fmt返回结构的大小

fmt 列表如下
编码格式,放在fmt第一位

Character Byte order Size and alignment
@(default) native order native 凑够4个字节
= native order standard 按原字节数
< little-endian standard 按原字节数
> big-endian standard 按原字节数
! network(same as >) standard 按原字节数
Format C Type Python 字节数
x pad byte no value 1
c char bytes of length 1 1
b signed char integer 1
B unsigned char integer 1
? _Bool bool 1
h short integer 2
H unsigned short integer 2
i int integer 4
I unsigned int integer 4
l long integer 4
L unsigned long integer 4
q long long integer 8
Q unsigned long long integer 8
f float float 4
d double float 8
s char[] bytes 1
p char[] bytes 1
P void * integer

注意:

  1. c,s和p按照bytes对象执行转码操作,但是在使用UTF-8编码时,也支持str对象。

  2. ‘?’按照C99中定义的_Bool类型转码。如果该类型不可用,可使用一个char冒充。

  3. ‘q’和’Q’仅在64位系统上有用。

1
2
s = struct.pack('B2sII', 0x04, 'aa', 0x01, 0x0e)
# 'B2sII'指的就是 一个unsigned short,一个char[2],一个unsigned int,一个unsigned int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# struct示例
import struct

fmt = '<3s3sHH' # < 是小字节序,3s3s 是两个 3 字节序列,HH 是两个 16 位二进制整数。
with open('filter.gif', 'rb') as fp:
img = memoryview(fp.read()) # 使用内存中的文件内容创建一个 memoryview 对象……

header = img[:10]
bytes(header) # 转换成字节序列,这只是为了显示;这里复制了 10 字节
# b'GIF89a+\x02\xe6\x00'
struct.unpack(fmt, header)
# (b'GIF', b'89a', 555, 230)
del header
del img