馬克的Python學習筆記#文件和I/O 3
讀寫壓縮的數據文件
gzip和bz2模塊可以解決這一類的問題。這兩個模塊都提供了open()的其他實現,可用於處理壓縮文件。比如我們想要把壓縮文件以文本的形式讀取,就可以這樣處理:
import gzip
with gzip.open(1.gz, rt) as f:
text = f.read()
或者讀取bz2就這樣:
import bz2
with bz2.open(1.bz2, rt) as f:
text = f.read()
同樣的,如果你想寫入壓縮數據,可以這樣:
#使用gzip壓縮
import gzip
with gzip.open(1.gz;, wt)m as f:
f.write(text)
#使用bz2壓縮
import bz2
with bz2.open(1.bz2, wt) as f:
f.write(text)
同樣,對於二進位文件的處理就用rb和wb模式就好
對於壓縮數據文件的讀寫大部分情況下都是簡單而直接的,但是注意:選擇正確的文件模式非常的重要。如果你沒有指定文件的模式,那麼系統會默認為二進位文件,which,會使期望接受文本的程序崩潰。gzip.open()和bz2.open()所接受的參數與內建的open()函數一樣,也支持encoding, errors, newline等關鍵字參數。同樣,當你寫入壓縮數據的是時候,壓縮級別也可以通過compresslevel關鍵字來指定。默認級別是9,代表著最高壓縮等級,低等級的壓縮可帶來更好的性能表現,但壓縮比就沒那麼大了。
對固定大小的記錄進行迭代
對於這種情況,我們可以利用iter()和functools.partial()來完成:
from functools import partial
def iterate_fixed():
RECORD_SIZE = 32
with open(somefile.data, rb) as f:
records = iter(partial(f.read, RECORD_SIZE), b)
for r in records:
print(r)
if __name__ == __main__:
iterate_fixed()
關於iter()這個函數還有一個特性是,如果傳遞一個可以調用的對象以及一個哨兵值給它,那麼它就可以創建一個迭代器。得到的迭代器會重複調用用戶提供的可迭代對象,直到返回哨兵值為止。並且,解決方案中展示的文件是以二進位模式打開的,對於讀取固定大小的記錄,這就是最常見的情況了。如果針對文本文件,那麼按行讀取更為普遍一些。
將二進位數據讀取到可變緩衝區中
對於這種情況,我們直接使用文件對象的readinto()就好
import os.path
def read_into_buffer(filename):
buf = bytearray(os.path.getsize(filename))
with open(filename, rb) as f:
f.readinto(buf)
return buf
def read_tobuffer():
buf = bytearray(os.path.getsize(filename))
print(buf)
m1 = memoryview(buf)
m2 = m1[-5:]
print(m2)
m2[:] = bWORLD
print(buf)
bytearray(bHello World)
if __name__ == __main__:
read_tobuffer()
文件對象的readinto()方法可以用來將數據填充到任何預分配好的數組中,但是與普通read()方法不同的是,readinto()是為已經存在的緩衝區填充內容,而不是分配新的對象然後再將它們返回,並且,你還可以用memoryview來對已存在的緩衝區進行切片處理,但是中間不涉及到任何拷貝操作,甚至我們還可以修改它的內容。
注意:使用f.readinto()時,必須要確保檢查它的返回值(實際讀取位元組數),如果位元組數小於緩衝區大小,這表示數據被截斷或者遭受到了破壞。
參考書目:
《Python CookBook》作者:【美】 David Beazley, Brian K. Jones
Github地址:
yidao620c/python3-cookbook
推薦閱讀: