python parse bit from bytes
先说结论
能用struct就用struct
能转成int就转成int
然后在int格式下 能 掩码& 移位>>。反而不是在bytes下。个人感觉这是一个“反直觉”的地方。不喜欢。所以记下来。
比如,解析flv文件。
按flv文件格式:
https://blog.csdn.net/byxdaz/article/details/53993791假设就解析前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 |
||
|
|
integer |
(1), (2) |
|
|
|
integer |
(2) |
|
|
|
bool |
(1) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(2) |
|
|
|
integer |
(3) |
|
|
|
integer |
(3) |
|
|
(6) |
float |
(4) |
|
|
|
float |
(4) |
|
|
|
float |
(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) # 同上
对第一句的几点说明
chuck[4] 从bytes里这样拿出来1个byte直接就给转成int了(又反直觉) format(int, 'b') 转成二进制格式的字符串,'101' zfill(8) 补足8位,在前面添加5个0 得到‘00000101’ 这种方法也比较简单,但是没用struct。数据少的时候可以用。但是其实不如位移操作直观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这方面设计的还是略显得反直觉。