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)...
这是一个不使用文本字符串转换来执行位运算的生成器。希望它能更有效率一点。:)
为了测试它,我将范围 (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)
这应该会加快一点速度......