非內存資源可以使用with
在python中逐行讀取大文件
在我們日常工作中,難免會有處理日志文件的時候,當文件小的時候,基本不用當心什么,直接用file.read()或readlines()就可以了,但是如果是將一個10G大小的日志文件讀取,即文件大於內存的大小,這么處理就有問題了,會將整個文件加載到內存中從而造成MemoryError … 也就是發生內存溢出。
對file對象進行迭代處理:
with open('file_name', 'r') as file:
for line in file:
print line
優點:
- with語句,文件對象在執行完代碼塊退出后自動關閉文件流,文件讀取數據發生異常,進行異常捕獲處理
- 對文件對象進行迭代時,在內部,它會緩沖IO(針對昂貴的IO操作進行優化)和內存管理,所以不必擔心大文件。
- 這才是 Pythonci 最完美的方式,既高效又快速
缺點:
- 每一行的數據內容不能大於內存大小,否則就會造成MemoryError
使用yield
正常情況使用上面這種方式就可以了,But,如果遇到整個文件只有一行,而且按照特定的字符進行分割,上面這種方式則不行了,這時候yield就非常有用了。
舉個栗子,log的形式是這樣子的。
- 2018-06-18 16:12:08,289 - main - DEBUG - Do something{|}…..
- 以{|}做為分割符。
def read_line(filename, split, size):
with open(filename, 'r+') as file:
buff = ''
while True:
while split in buff:
position = buff.index(split)
yield buff[:position]
buff = buff[(position +len(split)):]
chunk = file.read(size)
if not chunk:
yield buff
break
buff = buff +chunk
優點:
- 不在限制每行數據的大小,即使整個大文件只有一行。
缺點:
- 速度比上面這種方式要慢。
- 解析一下:
- 首先:定義一個緩沖區buff
- 循環判斷,如果split分割符在緩沖區buff,則進行查找分割符出現的位置,並yield回去。
- 將buff更新,繼續第二步
- 如果split分割符不在緩沖區buff,則read(size)個字符
- 如果chunk為空,則跳出循環,否則更新buff, 繼續第二步
- 所以我們需要使用那種方式呢,一般來說使用用第一種就可以了。碰到只有一行的數據,而且數據特別大的,就要考慮一下你是不是得罪那個程序員了,故意給你這樣一個文件。
讀取大幾G的大文件,可以利用生成器 generator
方法一: 將文件切分成小段,每次處理完小段,釋放內存
def read_in_block(file_path):
BLOCK_SIZE=1024
with open(file_path,"r") as f:
while True:
block =f.read(BLOCK_SIZE) #每次讀取固定長度到內存緩沖區
if block:
yield block
else:
return #如果讀取到文件末尾,則退出
for block in read_in_block(file_path):
print block
// 這個方法,速度很快(只有3s),但有個問題,若滿足了1024時,會將正好在1024位置的數據切開,雖然每個block都是str, 但無法直接得到每行的id,只能再切分。
def readInChunks(fileObj, chunkSize=4096):
"""
Lazy function to read a file piece by piece.
Default chunk size: 4kB.
"""
while 1:
data = fileObj.read(chunkSize)
if not data:
break
yield data
f = open('bigFile')
for chuck in readInChunks(f):
#do_something(chunk)
f.close()
python 實現大文件md5值計算
python 中使用hashlib模塊實現常見摘要算法,如md5、sha1等。
hashlib.md5(文件內容)實現了對文件的md5計算,注意參數為文件內容而不是文件路徑。
import hashlib
with open('2.jpeg','rb') as f:
data = f.read()
d5 = hashlib.md5(data)
print(d5.hexdigest())
md5()返回的是md5對象,不是md5值,通過hexdigest()方法獲取md5值。
md5計算時文件數據是放在內存中的,當我們計算一個大文件時,可以用update方法進行分步計算,每次添加部分文件數據進行計算,減少內存占用。
import hashlib
d5 = hashlib.md5()
with open('3.jpeg','rb') as f:
while True:
data = f.read(2024)
if not data:
break
d5.update(data) #update添加時會進行計算
print(d5.hexdigest()) #打印結果