在 python 中,當我們讀取一個本地 TextIO 文件時,最常用的方式是用 read
、readline
和 readlines
這三個方法。
fp.readlines()
with open(fp_name) as f_read: data = f_read.readlines() # The type of data is a list. # output: # ["<?xml version='1.0' encoding='utf8'?>\n", ...]
這種方式是將文件里面所有內容按行讀取到一個大列表中。對於小文件,這種方式其實挺方便,但對於大文件就會出現內存可能不足的情況,報 MemoryError
錯誤,或者消耗掉很客觀的內存資源。
fp.readline()
# 第一種寫法 with open(fp_name) as f_read: while True: line = f_read.readline() # The type of line is a string. if not line: break # 第二種寫法 with open(fp_name) as f_read: for line in f_read: ...
上面兩種寫法本質其實一樣,都是按行讀取文本,這種方式讀取文件會大大減少內存的消耗,一直讀到空行或者 EOF 標識才會被終止。一般大場景讀取文件這種方式性能和內存消耗比較好。
但這種方式也有一個缺陷,若文本是寫在一行,而不是多行,那么這兩種寫法不論哪一種,都和前面兩種方式一樣,將所有的文本內容【一行字符串】加載到內存當中,消耗大量的資源。那么這個時候處理單行十分大的文件,使用 fp.read()
這個最為底層的方法更好一些。
fp.read()
with open(fp_name) as f_read: data = f_read.read() # The type of data is a string. # output # '<?xml version=\'1.0\' encoding=\'utf8\'?>\n<OpenDRIVE><header revMajor="1" revMinor="4" name="" version="1.00" date="01/01/1970 17:45\n...\n'
不帶參數的情況下,這種方式將文本內容讀取為一個大的字符串對象,類似 readlines()
方法,只不過是輸出數據的格式不同。如果文本比較大,該方式會消耗很客觀的內存。
不過該方法有一個 size
參數,用於設置讀取文本的字節數,每次調用 fp.read (size) 會直接返回從當前位置往后讀取 size
大小的文件內容,不必等待任何換行符出現,這種方式有利於對單行大文本進行讀取處理。
我們可以使用這個分塊參數
這么讀取大文件,效果要比按行讀取
的方式在內存消耗上優化很多:
from functools import partial, wraps from typing import TextIO, Callable def chunked_file_reader(fp: TextIO, block_size: int=1024 * 8): for chunk in iter(partial(fp.read, block_size), ''): yield chunk def read_file(file_path: str) -> int: count: int = 0 with open(file_path) as f_read: for chunk in chunked_file_reader(f_read): count += 1 print(chunk) return count
利用迭代器
和生成器
構造一個可復用的分塊讀取方法,然后就可以方便的控制每次讀取的字節大小,在內存的占用以及代碼的執行性能上都會有不錯的表現。