讀取二進制文件並遍歷每一個字節

在Python中,如何讀取二進制文件並在該文件的每一個字節上循環? html


#1樓

Python 2.4及更早版本 python

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

Python 2.5-2.7 數組

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

請注意,with語句在2.5如下的Python版本中不可用。 要在v 2.5中使用它,您須要導入它: 函數

from __future__ import with_statement

在2.6中是不須要的。 oop

Python 3 性能

在Python 3中,這有點不一樣。 咱們將再也不以字節模式而是字節對象從流中獲取原始字符,所以咱們須要更改條件: spa

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之間兼容,而無需進行任何更改。 若是從字節模式更改成文本模式或相反,也能夠避免更改條件。 code

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

#2樓

若是文件不是太大,則將其保存在內存中是一個問題: htm

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

其中process_byte表示要對傳入的字節執行的某些操做。 對象

若是要一次處理一個塊:

with open("filename", "rb") as f:
    bytes_read = f.read(CHUNKSIZE)
    while bytes_read:
        for b in bytes_read:
            process_byte(b)
        bytes_read = f.read(CHUNKSIZE)

with語句在Python 2.5及更高版本中可用。


#3樓

該生成器從文件中產生字節,並分塊讀取文件:

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文檔。


#4樓

總結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緩衝區-無需讀取塊
  • 乾式原理-不要重複讀取行
  • with語句可確保關閉文件乾淨
  • 若是沒有更多的字節(不是字節爲零),則「 byte」的計算結果爲false

或使用JF 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)

#5樓

要讀取文件(一次一個字節(忽略緩衝)),可使用內置兩個參數的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會自動關閉文件-包括下面的代碼引起異常的狀況。

儘管默認狀況下存在內部緩衝,可是每次處理一個字節仍然效率低下。 例如,這是blackhole.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

它處理〜1.5 Gb / s的chunksize == 32768個人機器,只〜7.5 MB/秒chunksize == 1 。 也就是說,一次讀取一個字節要慢200倍。 考慮到這一點,若是你能夠重寫你的處理同時使用多個字節, 若是你須要的性能。

mmap容許您同時將文件視爲bytearray數組和文件對象。 若是您須要訪問兩個接口,它能夠替代將整個文件加載到內存中的方法。 特別是,您可使用普通for -loop一次遍歷一個內存映射文件一個字節:

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快一個數量級。

相關文章
相關標籤/搜索