在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
利用迭代器
和生成器
構造一個可複用的分塊讀取方法,然後就可以方便的控制每次讀取的位元組大小,在記憶體的佔用以及程式碼的執行效能上都會有不錯的表現。
本作品採用《CC 協議》,轉載必須註明作者和本文連結