使用 Python 讀取 8 GB 大小的檔案

發表於2016-05-31

筆試問題

如何使用Python讀取1個8GB大小的檔案,這個問題其實在筆試中會經常遇到的1個題目。對於在Python中讀取檔案的操作,一般我們會這樣來操作:

下面我們來找1個比較大的檔案,比如1個nginx的日誌檔案,記得之前有一次公司的1天的nginx日誌檔案解壓為3GB大小,不得不對其進行切分。

發現問題

這裡我們找到了1個3G大小的檔案。接下來,我們使用普通的讀取方式來檢視該檔案的內容:

我們可以看到1個MemoryError的錯誤,說明該無檔案無法被裝載在記憶體中發生溢位了。
下面我們來思考下為什麼記憶體會溢位了,在我們開啟檔案的時候並沒有發生任何異常,而在我們呼叫read方法時才出現問題。我們知道,檔案物件的read方法會嘗試將所有內容以1行的形式讀入,顯然這種方式對於大檔案是不可行的。

解決方案

在Python中,除了使用read方法讀取檔案內容外,還有另外2個方法readline和readlines也可以進行內容的讀取。
既然預設read方法是一次性的將內容都讀取到記憶體中,那麼我們是否可以指定其每次讀取的長度來解決這個問題呢?

而readlines會返回每1行讀取的內容的列表,因此有一定風險的。

那麼,我們每次讀取1行總可以了把。這樣我們可以通過如下的方式來進行:

我們通過1個無限迴圈的方式來進行讀取。結果發現,使用readlines的方式還是會導致記憶體不足的情況發生,而通過讀取指定位元組的方式則可以處理完這個檔案。
在上面的解決方案中,我們需要手動處理檔案讀取的大小,並在合適的情況退出讀取的操作。
那麼,我們有沒有更好的解決方案呢?實際上是有的,在Python的手冊中,有1個xreadlines的方法,這個方法就類比range和xrange函式的區別。這個方法返回類似iter(f)的字串,但是遺憾的是該方法在Python版本2.3中已經被淘汰了,官方建議我們使用for語句來替代:

通過這種方式,Python將處理檔案物件為1個迭代器,並自動使用快取IO和記憶體管理,這樣我們就不需要關注大的檔案了。

參考檔案:

http://stackoverflow.com/questions/8009882/how-to-read-large-file-line-by-line-in-python

相關文章