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

x

pad byte

no value

   

c

char

bytes of length 1

 

b

signed char

integer

(1), (2)

B

unsigned char

integer

(2)

?

_Bool

bool

(1)

h

short

integer

(2)

H

unsigned short

integer

(2)

i

int

integer

(2)

I

unsigned int

integer

(2)

l

long

integer

(2)

L

unsigned long

integer

(2)

q

long long

integer

(2)

Q

unsigned long long

integer

(2)

n

ssize_t

integer

 

(3)

N

size_t

integer

 

(3)

e

(6)

float

(4)

f

float

float

(4)

d

double

float

(4)

s

char[]

bytes

   

p

char[]

bytes

   

P

void *

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这方面设计的还是略显得反直觉。