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

2009-06-23 21:26:52
问题评论:

回答:

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

通过 chrispy 的建议︰

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

请注意,使用语句不低于 2.5 的 Python 版本中可用。您将需要将其导入的 2.5 v 中使用它︰

from __future__ import with_statement

在 2.6 中,则不需要。

在 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""计算结果为 false。这使得代码兼容 2.6 之间 3.x 无需进行任何更改。它还将保存您更改条件,如果从字节模式转到文本或相反。

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

EOF 吗?在 Python 中?我认为您是"虽然 len(byte) > 0:"或类似。

使用语句将整理此代码。

几个简单的 Python 样式的 n 它 pickish 事情︰ 公共 (和 PEP8 样式),使用空字符串的值为 false,因此只是在于它的"字节时:..."则不然。它也很常见,可以在 Python 中使用"while True"的用法,所以您不需要重复 f.read(1)。像"而真︰ 字节 = f.read(1);如果不是字节︰ 中断..."。

@John Montgomery,"它将相当时读取零": 不,它不会。正在读取字符、 不是整数,并从 x00' 到 'xff' 没有字符值为 Python 中曾经假。只有没有字符,如下所示 ',将为 False,并会耗尽您的输入后才获得的。

Byte-wise 读取文件时性能非常棘手的工作。这不可能在 python 中可用的最佳解决方案。应小心使用此代码。

从文件中读取该文件以块的形式将此生成器生成字节︰

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 文档信息.

+ 1。这是一个非常有用的解决方案,如果是经常做的事情我想。我将可能更改它使 bytes_from_file 采取类似于文件的对象,所以我可以使用它与所有种类的"流"。

+ 1 我喜欢此解决方案超过所有其他因为自己一次做f.read(...)调用您的代码中。我喜欢遵循原则。

因此您将执行的块区大小文件大小/时间打开/关闭文件?我会建议将文件句柄传递到生成器。

打开 (和关闭) 文件一次。然后是,f 可能也只是传递给函数。

它是一台发电机,因此元素是第二次请求代码的 @SergeyRomanovsky 后,将继续yield b,在with open(...)部件,使文件保持打开状态,直到用尽生成器

如果该文件不是太大,它保存在内存中是问题︰

bytes_read = open("filename", "rb").read()
for b in bytes_read:
    process_byte(b)

您想要在传入的字节执行其中 process_byte 表示某个操作。

如果您想要一次处理文本块︰

file = open("filename", "rb")
try:
    bytes_read = file.read(CHUNKSIZE)
    while bytes_read:
        for b in bytes_read:
            process_byte(b)
        bytes_read = file.read(CHUNKSIZE)
finally:
    file.close()

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

from functools import partial

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

它调用file.read(1) ,直到它返回 nothing b'' (空 bytestring)。内存不增长较大的文件不受限制。可以传递buffering=0open(),可以禁用缓冲 — — 它保证每次迭代中读取该只有一个字节。

with的语句将自动关闭该文件 — — 包括这种情况,下面的代码引发异常。

默认的内部缓冲的存在,尽管是仍然低下,一次处理一个字节。例如,下面是 eats 一切都将为其给定的blackhole.py实用程序︰

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

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

示例︰

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

如果处理与默认bufsize在我的机器和仅~7.5 MB/s ~1.5 GB/s bufsize=1即是 200 倍慢一次读取一个字节。将其考虑如果您可以重写您的处理时间,如果您需要的性能在使用多个字节。

mmap允许您同时将视为bytearray和文件对象的文件。它可以作为加载整个文件在内存中的,如果您需要访问这两个接口的一种替代方法。特别是,可以循环一个字节一次通过仅使用普通for内存映射文件的循环︰

from mmap import ACCESS_READ, mmap

with open(filename, 'rb') as f, mmap(f.fileno(), 0, access=ACCESS_READ) as mm:
    for byte in mm: # 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 内部的缓冲区读取数据块不需要
  • 干原则-不要重复读取的行
  • 使用语句来确保清理文件关闭
  • 字节计算结果为 false,当有更多字节 (而不是在一个字节为 0)

J.F.Sebastians 解决方案用于提高速度或

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)

您可以使用iter(partial(file.read, 1), b'')而不是while循环。

@J.F.Sebastian-您是 100%正确的速度可能更快

链接的回答说,每次的阅读处理/1 个字节是 Python 中仍然缓慢即使缓冲读取。如果几个字节,一次可以处理的示例的链接的回答中可以大大提高性能︰ 1.5 g B/s 与 7.5 MB/s。

请输入您的翻译

Reading binary file in Python and looping over each byte

确认取消