在Python中,如何讀取二進制文件並在該文件的每一個字節上循環? html
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)
若是文件不是太大,則將其保存在內存中是一個問題: 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及更高版本中可用。
該生成器從文件中產生字節,並分塊讀取文件:
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)
總結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及更高版本,由於:
或使用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)
要讀取文件(一次一個字節(忽略緩衝)),可使用內置兩個參數的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
快一個數量級。