在Python中,我如何在二进制文件中读取并循环该文件的每个字节?


当前回答

对于大尺寸,我认为使用生成器不会不好,这个答案是为了读取像文件这样的东西,虽然@codeapp有一个类似的答案,我认为删除内部循环会更有意义。

def read_chunk(file_object, chunk_size=125):
    while True:
        file =  file_object.read(chunk_size)
        if not file:
            break
        yield file


#sample use 
buffer = io.BytesIO()
file = open('myfile', 'r')
for chunk in read_chunk(file):
    buffer.write(chunk)
buffer.seek(0)
// save the file or do whatever you want here

你仍然可以使用它作为一个正常的列表,我不认为这是任何用途,但是

file_list = list(read_chunk(file, chunk_size=10000))
for i in file_list:
    # do something

然后得到每个数据块的索引

for index, chunk in enumurate(read_chunk(file, chunk_size=10000)):
    #use the index as a number index
    # you can try and get the size of each chunk with this 
    length = len(chunk)

注意,要注意文件的大小,chunk_size总是以字节为单位。

其他回答

总结chrispy, Skurmedel, Ben Hoyt和Peter Hansen的所有出色之处,这将是一次一个字节处理二进制文件的最佳解决方案:

with open("myfile", "rb") as f:
    while True:
        byte = f.read(1)
        if not byte:
            break
        do_stuff_with(ord(byte))

对于python 2.6及以上版本,因为:

Python内部缓冲区-不需要读取块 DRY原则——不重复读行 语句确保干净的文件关闭 当没有更多字节时,'byte'的计算结果为false(当字节为零时不是)

或使用J. F.塞巴斯蒂安的解决方案提高速度

from functools import partial

with open(filename, 'rb') as file:
    for byte in iter(partial(file.read, 1), b''):
        # Do stuff with byte

或者如果你想把它作为一个生成器函数,就像codeape演示的那样:

def bytes_from_file(filename):
    with open(filename, "rb") as f:
        while True:
            byte = f.read(1)
            if not byte:
                break
            yield(ord(byte))

# example:
for b in bytes_from_file('filename'):
    do_stuff_with(b)

在尝试了以上所有方法并使用@Aaron Hall的答案后,我在一台运行windows 10, 8gb RAM和Python 3.5 32位的计算机上得到了一个~ 90mb的文件的内存错误。我的一位同事推荐我使用numpy,它的效果非常好。

到目前为止,读取整个二进制文件(我测试过)的最快速度是:

import numpy as np

file = "binary_file.bin"
data = np.fromfile(file, 'u1')

参考

比目前任何方法都要快。希望它能帮助到一些人!

Python >= 3.8

多亏了walrus操作符(:=),解决方案非常短。我们从文件中读取bytes对象,并将它们赋值给变量byte

with open("myfile", "rb") as f:
    while (byte := f.read(1)):
        # Do stuff with byte.

Python >= 3

在较旧的Python 3版本中,我们必须使用更详细的方式:

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte != b"":
        # Do stuff with byte.
        byte = f.read(1)

或者像benhoyt说的,跳过不相等,利用b""的值为假的事实。这使得代码在2.6和3之间兼容。X没有任何变化。如果从字节模式转换为文本模式或相反模式,也可以避免更改条件。

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte:
        # Do stuff with byte.
        byte = f.read(1)

Python >= 2.5

在Python 2中,这有点不同。这里我们得到的不是bytes对象,而是原始字符:

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte != "":
        # Do stuff with byte.
        byte = f.read(1)

注意,with语句在Python 2.5以下版本中不可用。要在v 2.5中使用它,你需要导入它:

from __future__ import with_statement

在2.6中不需要这样做。

Python 2.4及更早版本

f = open("myfile", "rb")
try:
    byte = f.read(1)
    while byte != "":
        # Do stuff with byte.
        byte = f.read(1)
finally:
    f.close()

Python 3,一次读取所有文件:

with open("filename", "rb") as binary_file:
    # Read the whole file at once
    data = binary_file.read()
    print(data)

你可以使用data变量迭代任何你想要的东西。

如果要读取大量二进制数据,可能需要考虑struct模块。它被记录为“在C和Python类型之间”转换,但当然,字节就是字节,它们是否被创建为C类型并不重要。例如,如果你的二进制数据包含两个2字节整数和一个4字节整数,你可以这样读取它们(例子来自struct文档):

>>> struct.unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)

您可能会发现这比显式遍历文件内容更方便、更快,或者两者兼而有之。