python parse bit from bytes
先说结论
能用struct就用struct
能转成int就转成int
然后在int格式下 能 掩码& 移位>>。反而不是在bytes下。个人感觉这是一个“反直觉”的地方。不喜欢。所以记下来。
比如,解析flv文件。
按flv文件格式:
假设就解析前9byte
import struct
f_stream = open(‘./xxx.flv’, 'rb') chunk = stream.read(9)
1 最简洁的方法:
先用标准库的struct.unpack解出整体结构
https://docs.python.org/3/library/struct.html
the packed value is platform-dependent.
Format |
C Type |
Python type |
Standard size |
Notes |
---|---|---|---|---|
|
pad byte |
no value |
||
|
|
bytes of length 1 |
1 |
|
|
|
integer |
1 |
(1), (2) |
|
|
integer |
1 |
(2) |
|
|
bool |
1 |
(1) |
|
|
integer |
2 |
(2) |
|
|
integer |
2 |
(2) |
|
|
integer |
4 |
(2) |
|
|
integer |
4 |
(2) |
|
|
integer |
4 |
(2) |
|
|
integer |
4 |
(2) |
|
|
integer |
8 |
(2) |
|
|
integer |
8 |
(2) |
|
|
integer |
(3) |
|
|
|
integer |
(3) |
|
|
(6) |
float |
2 |
(4) |
|
|
float |
4 |
(4) |
|
|
float |
8 |
(4) |
|
|
bytes |
||
|
|
bytes |
||
|
|
integer |
(5) |
C
我们这样写
format_str = '>3sBBI' flv, version, stream_type_bits, len_header = struct.unpack(format_str, chunk)
注意倒数第二个stream_type_bits 给搞成了“B” 1 byte的 integer:
下面就可以位移了:
#对int才可以& 和>> has_audio = (stream_type_bits & 0x7) >> 2 has_video = stream_type_bits & 0x1
这样是最简单的。但对int 进行 位操作,而不是对bytes进行位操作,感觉非常反直觉。
2 麻烦点的办法1
不用struct。直接拿出int然后转成string,用string取bit,再转成int
看着绕,但是写码也很简洁:
stream_type_bits = format(chuck[4], 'b').zfill(8) has_audio = int(stream_type_bits[5], 2) #按bit字符串,按二进制转成int has_video = int(stream_type_bits[7], 2) # 同上
对第一句的几点说明
3 麻烦点的办法2
读出1个bytes 然后用bitarray
from bitarray import bitarray #format_str = '>3sBBI' format_str = '>3sBsI' flv, version, stream_type_bits, len_header = struct.unpack(format_str, chunk) stream_type = bitarray(endian='big') stream_type.frombytes(stream_type_bytes) has_video, has_audio = stream_type[-1], stream_type[-3]
如果需要修改bit,这样比较方便。所以也放在这了
感觉python这方面设计的还是略显得反直觉。