Python - 从二进制文件中读取10位整数

Jea*_*tin 6 python binary file-io

我有一个包含10位整数流的二进制文件.我想读它并将值存储在列表中.

它使用以下代码,它读取my_file并填充pixels整数值:

file = open("my_file", "rb")

pixels = []
new10bitsByte = ""

try:
    byte = file.read(1)
    while byte:
        bits = bin(ord(byte))[2:].rjust(8, '0')
        for bit in reversed(bits):
            new10bitsByte += bit
            if len(new10bitsByte) == 10:
                pixels.append(int(new10bitsByte[::-1], 2))
                new10bitsByte = ""             
    byte = file.read(1)

finally:
    file.close()
Run Code Online (Sandbox Code Playgroud)

将字节读入位并将其读回"10位"字节似乎并不优雅.有没有更好的方法呢?

使用8位或16位整数,我可以直接使用file.read(size)并将结果转换为int.但是在这里,因为每个值都存储在1.25字节,我需要像file.read(1.25)...

PM *_*ing 3

这是一个不使用文本字符串转换来执行位运算的生成器。希望它能更有效率一点。:)

为了测试它,我将范围 (1024) 中的所有数字写入BytesIO流,其行为类似于二进制文件。

from io import BytesIO

def tenbitread(f):
    ''' Generate 10 bit (unsigned) integers from a binary file '''
    while True:
        b = f.read(5)
        if len(b) == 0:
            break
        n = int.from_bytes(b, 'big')

        #Split n into 4 10 bit integers
        t = []
        for i in range(4):
            t.append(n & 0x3ff)
            n >>= 10
        yield from reversed(t)

# Make some test data: all the integers in range(1024),
# and save it to a byte stream
buff = BytesIO()

maxi = 1024
n = 0
for i in range(maxi):
    n = (n << 10) | i
    #Convert the 40 bit integer to 5 bytes & write them
    if i % 4 == 3:
        buff.write(n.to_bytes(5, 'big'))
        n = 0

# Rewind the stream so we can read from it
buff.seek(0)

# Read the data in 10 bit chunks
a = list(tenbitread(buff))

# Check it 
print(a == list(range(maxi)))    
Run Code Online (Sandbox Code Playgroud)

输出

True
Run Code Online (Sandbox Code Playgroud)

这样做list(tenbitread(buff))是将生成器输出转换为列表的最简单方法,但您可以轻松地迭代这些值,例如

for v in tenbitread(buff):
Run Code Online (Sandbox Code Playgroud)

或者

for i, v in enumerate(tenbitread(buff)):
Run Code Online (Sandbox Code Playgroud)

如果您想要索引以及数据值。


这是生成器的小端版本,它给出与您的代码相同的结果。

def tenbitread(f):
    ''' Generate 10 bit (unsigned) integers from a binary file '''
    while True:
        b = f.read(5)
        if not len(b):
            break
        n = int.from_bytes(b, 'little')

        #Split n into 4 10 bit integers
        for i in range(4):
            yield n & 0x3ff
            n >>= 10
Run Code Online (Sandbox Code Playgroud)

我们可以通过“展开”for 循环来稍微改进这个版本,这让我们摆脱了最终的屏蔽和移位操作。

def tenbitread(f):
    ''' Generate 10 bit (unsigned) integers from a binary file '''
    while True:
        b = f.read(5)
        if not len(b):
            break
        n = int.from_bytes(b, 'little')

        #Split n into 4 10 bit integers
        yield n & 0x3ff
        n >>= 10
        yield n & 0x3ff
        n >>= 10
        yield n & 0x3ff
        n >>= 10
        yield n 
Run Code Online (Sandbox Code Playgroud)

应该会加快一点速度......