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


当前回答

要读取一个文件-一次一个字节(忽略缓冲)-你可以使用双参数iter(callable, sentinel)内置函数:

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

它调用file.read(1),直到没有返回b”(空字节串)。对于大文件,内存不会无限增长。你可以将buffering=0传递给open()来禁用缓冲——它保证每次迭代只读取一个字节(慢)。

With-statement自动关闭文件——包括下面的代码引发异常的情况。

尽管默认情况下存在内部缓冲,但一次处理一个字节的效率仍然很低。例如,下面是黑洞.py实用程序,它会吃掉所有给定的东西:

#!/usr/bin/env python3
"""Discard all input. `cat > /dev/null` analog."""
import sys
from functools import partial
from collections import deque

chunksize = int(sys.argv[1]) if len(sys.argv) > 1 else (1 << 15)
deque(iter(partial(sys.stdin.detach().read, chunksize), b''), maxlen=0)

例子:

$ dd if=/dev/zero bs=1M count=1000 | python3 blackhole.py

在我的机器上,当chunksize == 32768时,它处理大约1.5 GB/s,当chunksize == 1时,它只处理大约7.5 MB/s。也就是说,每次读取一个字节要慢200倍。考虑一下您是否可以重写处理以便一次使用多个字节,以及您是否需要性能。

Mmap允许您同时将文件视为bytearray和文件对象。如果需要访问两个接口,它可以作为在内存中加载整个文件的替代方案。特别是,你可以在一个内存映射文件上一次迭代一个字节,只使用简单的for循环:

from mmap import ACCESS_READ, mmap

with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
    for byte in s: # length is equal to the current file size
        # Do stuff with byte

Mmap支持切片表示法。例如,mm[i:i+len]返回文件中从位置i开始的len字节。Python 3.2之前不支持上下文管理器协议;在这种情况下,需要显式调用mm.close()。使用mmap遍历每个字节比file.read(1)消耗更多的内存,但是mmap要快一个数量级。

其他回答

要读取一个文件-一次一个字节(忽略缓冲)-你可以使用双参数iter(callable, sentinel)内置函数:

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

它调用file.read(1),直到没有返回b”(空字节串)。对于大文件,内存不会无限增长。你可以将buffering=0传递给open()来禁用缓冲——它保证每次迭代只读取一个字节(慢)。

With-statement自动关闭文件——包括下面的代码引发异常的情况。

尽管默认情况下存在内部缓冲,但一次处理一个字节的效率仍然很低。例如,下面是黑洞.py实用程序,它会吃掉所有给定的东西:

#!/usr/bin/env python3
"""Discard all input. `cat > /dev/null` analog."""
import sys
from functools import partial
from collections import deque

chunksize = int(sys.argv[1]) if len(sys.argv) > 1 else (1 << 15)
deque(iter(partial(sys.stdin.detach().read, chunksize), b''), maxlen=0)

例子:

$ dd if=/dev/zero bs=1M count=1000 | python3 blackhole.py

在我的机器上,当chunksize == 32768时,它处理大约1.5 GB/s,当chunksize == 1时,它只处理大约7.5 MB/s。也就是说,每次读取一个字节要慢200倍。考虑一下您是否可以重写处理以便一次使用多个字节,以及您是否需要性能。

Mmap允许您同时将文件视为bytearray和文件对象。如果需要访问两个接口,它可以作为在内存中加载整个文件的替代方案。特别是,你可以在一个内存映射文件上一次迭代一个字节,只使用简单的for循环:

from mmap import ACCESS_READ, mmap

with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
    for byte in s: # length is equal to the current file size
        # Do stuff with byte

Mmap支持切片表示法。例如,mm[i:i+len]返回文件中从位置i开始的len字节。Python 3.2之前不支持上下文管理器协议;在这种情况下,需要显式调用mm.close()。使用mmap遍历每个字节比file.read(1)消耗更多的内存,但是mmap要快一个数量级。

总结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)

下面是一个使用Numpy fromfile读取网络端数据的例子:

dtheader= np.dtype([('Start Name','b', (4,)),
                ('Message Type', np.int32, (1,)),
                ('Instance', np.int32, (1,)),
                ('NumItems', np.int32, (1,)),
                ('Length', np.int32, (1,)),
                ('ComplexArray', np.int32, (1,))])
dtheader=dtheader.newbyteorder('>')

headerinfo = np.fromfile(iqfile, dtype=dtheader, count=1)

print(raw['Start Name'])

我希望这能有所帮助。问题是fromfile不能识别和EOF,并允许对任意大小的文件优雅地跳出循环。

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

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

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

这个生成器从文件中产生字节,以块的形式读取文件:

def bytes_from_file(filename, chunksize=8192):
    with open(filename, "rb") as f:
        while True:
            chunk = f.read(chunksize)
            if chunk:
                for b in chunk:
                    yield b
            else:
                break

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

有关迭代器和生成器的信息,请参阅Python文档。