python讀寫檔案的api都很簡單,一不留神就容易踩」坑「。筆者記錄一次踩坑歷程,並且給了一些總結,希望到大家在使用python的過程之中,能夠避免一些可能產生隱患的**。隨手搜尋python讀寫檔案的教程,很經常看到read()與readlines()這對函式。所以我們會常常看到如下**:
with open(file_path, 'rb') as f:
sha1obj.update(f.read())
or
with open(file_path, 'rb') as f:
for line in f.readlines():
print(line)
這對方法在讀取小檔案時確實不會產生什麼異常,但是一旦讀取大檔案,很容易會產生memoryerror,也就是記憶體溢位的問題。
####why memory error?
我們首先來看看這兩個方法:
當預設引數size=-1時,read方法會讀取直到eof,當檔案大小大於可用記憶體時,自然會發生記憶體溢位的錯誤。
同樣的,readlines會構造乙個list。list而不是iter,所以所有的內容都會儲存在記憶體之上,同樣也會發生記憶體溢位的錯誤。
在實際執行的系統之中如果寫出上述**是十分危險的,這種」坑「十分隱蔽。所以接下來我們來了解一下正確用,正確的用法也很簡單,依照api之中對函式的描述來進行對應的編碼就ok了:
如果是二進位制檔案推薦用如下這種寫法,可以自己指定緩衝區有多少byte。顯然緩衝區越大,讀取速度越快。
with open(file_path, 'rb') as f:
while true:
buf = f.read(1024)
if buf:
sha1obj.update(buf)
else:
break
而如果是文字檔案,則可以用readline方法或直接迭代檔案(python這裡封裝了乙個語法糖,二者的內生邏輯一致,不過顯然迭代檔案的寫法更pythonic)每次讀取一行,效率是比較低的。筆者簡單測試了一下,在3g檔案之下,大概效能和前者差了20%.
with open(file_path, 'rb') as f:
while true:
line = f.readline()
if buf:
print(line)
else:
break
with open(file_path, 'rb') as f:
for line in f:
print(line)
對於python**的記憶體占用問題,對於**進行記憶體監控十分必要。這裡筆者這裡推薦兩個小工具來檢測python**的記憶體占用。
####memory_profiler
首先先用pip安裝memory_profiler
pip install memory_profiler
memory_profiler是利用python的裝飾器工作的,所以我們需要在進行測試的函式上新增裝飾器。
from hashlib import sha1
import sys
@profile
def my_func():
sha1obj = sha1()
with open(sys.argv[1], 'rb') as f:
while true:
buf = f.read(10 * 1024 * 1024)
if buf:
sha1obj.update(buf)
else:
break
print(sha1obj.hexdigest())
if __name__ == '__main__':
my_func()
之後在執行**時加上** -m memory_profiler**
就可以了解函式每一步**的記憶體占用了
依樣畫葫蘆,仍然是通過pip先安裝guppy
pip install guppy
之後可以在**之中利用guppy直接列印出對應各種python型別(list、tuple、dict等)分別建立了多少物件,占用了多少記憶體。
from guppy import hpy
import sys
def my_func():
mem = hpy()
with open(sys.argv[1], 'rb') as f:
while true:
buf = f.read(10 * 1024 * 1024)
if buf:
print(mem.heap())
else:
break
如下圖所示,可以看到列印出對應的記憶體占用資料:
通過上述兩種工具guppy與memory_profiler可以很好地來監控python**執行時的記憶體占用問題。
python是一門崇尚簡潔的語言,但是正是因為它的簡潔反而更多了許多需要仔細推敲和思考的細節。希望大家在日常工作與學習之中也能多對一些細節進行總結,少踩一些不必要的「坑」。
python讀取大檔案的方法及mmap記憶體對映模組
python計算檔案的行數和讀取某一行內容的實現方法 最簡單的辦法是把檔案讀入乙個大的列表中,然後統計列表的長度.如果檔案的路徑是以引數的形式filepath傳遞的,那麼只用一行 就可以完成我們的需求了 使用python內建的模組mmap可以處理大檔案 注意 mmap在mac下的支援不是很好,有些函...
python 讀取大檔案
以前一直沒有關注過python讀取大檔案的問題,因為一直都是順順暢暢地讀取了檔案。直到今天有人問我python怎麼讀取檔案出現了記憶體不足的錯誤?我才發現原來大檔案 gb級別 的讀取和普通檔案的讀取是不一樣的。下面介紹三種我親測可用的方法。這裡的檔案型別可以是txt,dat等型別的檔案。用read ...
python讀取大檔案
最近在學習python的過程中接觸到了python對檔案的讀取。python讀取檔案一般情況是利用open 函式以及read 函式來完成 f open filename,r f.read 這種方法讀取小檔案,即讀取遠遠大小小於記憶體的檔案顯然沒有什麼問題。但是如果是將乙個10g大小的日誌檔案讀取,即...