3分鐘學會,學會用Python正確讀取大文件

3分鐘學會,學會用Python正確讀取大文件

文件讀寫屬於一種常見的IO操作,由於操作系統將底層操作磁盤的接口向上封裝爲一種通用接口,因此Python中讀寫文件的基本方法和JAVA、PHP等高級編程語言一樣,先請求操作系統打開一個文件描述符,通過操作系統提供的接口從這個文件對象中讀取數據,或者把數據寫入這個文件中,最後當文件讀寫操作完成後關閉文件。

需要注意的是文件讀寫完成後必須及時關閉文件,一方面打開的文件會佔用操作系統的資源,並且操作系統同一時間能打開的文件數量也是有限制的,比如Linux操作系統中我們可以使用ulimit -n命令查看最多可打開文件的數量。另一方面在寫文件時,操作系統是把數據放到內存緩衝區異步寫入磁盤中,並不會立刻把數據全部寫入磁盤,而調用close()方法可以使操作系統把沒有寫入磁盤的數據全部寫入磁盤中,防止數據丟失的情況。接下來我們先看下正確的文件打開方式。

文件打開的幾種方式

Python內置了open()方法打開了一個文件,如下所示。文件打開模式有'r'、'w'、'a'、'r+'、'w+'、'a+'、'b'等,'r'只讀模式打開文件,並將文件指針指向文件頭,如果文件不存在會報錯;'w'只寫模式打開文件,並將文件指針指向文件頭,如果文件存在則將其內容清空,不存在則創建;'a'以只追加可寫模式打開文件,並將文件指針指向文件尾部,如果文件不存在則創建。對應於open()方法打開文件需要有close()方法關閉文件。

f = open('/mnt/media/log.txt', 'r')
f.read()
f.close()

由於讀寫文件時都有可能產生IOError,比如文件不存在的情況,此時open()方法會拋出一個IOError的異常,那麼後面的f.close()就不會被調用。爲了保證無論是否出錯都能正確地關閉文件,我們可以使用try ... finally來實現。

try:
 f = open('/mnt/media/log.txt', 'r')
 f.read()
finally:
 if f:
 f.close()

由於try ... finally方式實現較爲繁瑣,Python引入了with語句會自動調用f.close()方法,使得代碼更簡潔。

with open('/mnt/media/log.txt', 'r') as f:
 f.read()

大文件讀取幾種方式

對文件的讀取操作是將文件中的數據加載到內存中,那麼對於大文件的讀取,如果一次把文件中全部的內容全部加載到內存中顯然會耗盡系統的內容。我們看下Python中讀取文件常用的方法read()、readline()、readlines()對於大文件讀取的支持情況:read(size)方法是從文件當前位置起讀取size個字節,若無參數size,則表示讀取至文件結束爲止,如果文件比較小,用read()一次讀取文件較爲方便,但如果不能確定文件大小,反覆調用read(size)比較保險;readline()方法每次讀出一行內容,所以讀取時佔用內存小,比較適合大文件。readlines()方法讀取整個文件所有行,保存在一個列表list變量中,每行作爲一個元素,讀取大文件時比較佔內存。

說到大文件的讀取,有個linecache模塊,這裏要說明下的是這個模塊的優勢是通過緩存文件內容的方式來加快下次讀取文件的速度,所以需要耗費更多的內存,那麼以下是我在Linux發行版LEDE+MT7688的環境下對readlines、linecache.getlines以及遍歷文件這三種方式在內存的使用情況下的對比:

在學習過程中有什麼不懂得可以加我的
python學習交流扣扣qun,784-758-214
羣裏有不錯的學習視頻教程、開發工具與電子書籍。
與你分享python企業當下人才需求及怎麼從零基礎學習好python,和學習什麼內容
count = len(open(filepath, 'r').readlines())
_________________________________________________________
count = = len(linecache.getline(filepath) )
_________________________________________________________
count = 0
for count, line in enumerate(open(filepath,'r')):
 pass
count += 1
________________________________________________
count = len([ "" for line in open("filename","r")])
不打開文件:Mem: 37648K used, 88184K free, 116K shrd, 0K buff, 12540K cached 
readlines讀取文件:Mem: 69560K used, 56272K free, 124K shrd, 0K buff, 27004K cached 
linecache.getlines讀取文件:Mem: 70396K used, 55436K free, 116K shrd, 0K buff, 26996K cached
遍歷方式讀取文件:Mem: 53032K used, 72800K free, 116K shrd, 0K buff, 27668K cached 

但是linecache.getlines在讀取文件的速度上是有絕對優勢的,因爲文件內容已經緩存在內存中了,下次讀取可以直接從內存中獲取,可以使用linecache.checkcache檢測文件在磁盤上是否發生了變化,如果變化了需要使用linecache.updatecache更新緩存。不過首次讀取文件需要打開文件,對於一個15M左右20000行的日誌文件三種方式差不多需要8、9秒的時間,但第二次讀取文件linecache.getlines方式是微秒級的。

readlines讀取文件:

time count 215794 type1 is 9.58759188652

time count 215794 type1 is 1.70862102509

time count 215794 type1 is 2.05462002754

time count 215794 type1 is 1.69754505157

time count 215813 type1 is 2.1633579731

time count 215813 type1 is 1.61879992485

遍歷方式讀取文件:

time count 215508 type2 is 8.8404238224

time count 215508 type3 is 2.22844409943

time count 215508 type2 is 2.19772100449

time count 215508 type3 is 2.57516384125

time count 215586 type2 is 2.12095785141

time count 215586 type3 is 2.55960321426

time count 215586 type2 is 2.1704659462

time count 215586 type3 is 2.11596107483

linecache.getlines讀取文件:

time count 214811 type4 is 8.19337201118

time count 214811 type4 is 6.50882720947e-05

time count 214811 type4 is 9.41753387451e-05

time count 214811 type4 is 6.69956207275e-05

time count 214811 type4 is 9.41753387451e-05

time count 214811 type4 is 6.89029693604e-05

覺得文章還可以的話不妨收藏起來慢慢看,有任何意見或者看法歡迎大家評論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章