在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, 繼續第二步

所以我們需要使用那種方式呢,一般來說使用用第一種就可以了。碰到只有一行的數據,而且數據特別大的,就要考慮一下你是不是得罪那個程序員了,故意給你這樣一個文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM