HOWTO · Python
如何在 Python 中從檔案讀取特定行
Python 提供多種讀取檔案中特定行的方法:小型檔案可使用 readlines(),大型檔案可使用 enumerate() 逐行掃描;若要重複存取同一檔案中的行,可使用 linecache,但快取內容仍會占用記憶體。
本頁內容
要從 Python 文字檔讀取一行或多行特定內容,請先確認行號是由人提供,還是來自 Python 程式碼。人使用的行號通常從 1 開始,清單索引則從 0 開始。對於小型檔案,readlines() 會載入所有行,方便直接依索引存取。大型檔案可用 enumerate() 逐行掃描。若要重複查詢行號,linecache 可依行號讀取並快取檔案資料,因此並非固定記憶體用量的解法。
請先選定行號的計算方式
如果有人要讀取第 3 行,對應的清單索引就是 3 - 1,也就是 2。enumerate() 預設也從索引 0 開始。相較之下,linecache.getline(path, 3) 使用從 1 開始的人用行號 3。清楚區分這些計算方式,可避免行號偏差一位。文字行通常包含結尾的換行字元;只有在顯示內容或比較時不希望保留這個空白,才需要將它移除。
使用 readlines() 讀取小型檔案中的指定行
readlines() 會傳回包含每一行的清單;若原行有換行字元,也會一併保留。當檔案大小適合載入記憶體,且你可能會存取多個位置時,這種做法很方便。以下完整範例會建立暫存文字檔並印出第三行:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as folder:
path = Path(folder) / "notes.txt"
path.write_text("first\nsecond\nthird\nfourth\n", encoding="utf-8")
with path.open(encoding="utf-8") as file:
lines = file.readlines()
print(lines[2].rstrip("\n"))
若要取得從 first_line 到 last_line 的人用行號範圍(含頭尾),請使用切片 lines[first_line - 1:last_line]。切片的結尾索引不包含在結果中,因此直接以人用的最後一行行號作為結尾索引即可。若指定的行可能不存在,請先確認索引小於 len(lines),再進行索引存取。
使用 enumerate() 逐行讀取大型檔案中的指定行
直接逐行走訪檔案,便不必建立包含所有行的清單。讀取每一行時,enumerate(file) 會提供從 0 開始的索引;若要顯示人用行號,請加上 1。要讀到較後面的行,仍須先經過前面的行,因此這種方式適合降低記憶體使用量,不能直接跳到遠處的行。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as folder:
path = Path(folder) / "events.txt"
path.write_text("start\nready\nconnected\nfinished\n", encoding="utf-8")
wanted = {2, 4}
with path.open(encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1):
if line_number in wanted:
print(line_number, line.rstrip("\n"))
if line_number >= max(wanted):
break
此處的 start=1 會讓迴圈變數直接代表人用行號,選取條件因此更容易閱讀。如果檔案行數少於指定行號,迴圈會直接結束,不會印出那些不存在的行。
使用 linecache 重複存取檔案中的行
若程式會依檔案中從 1 開始的行號重複查詢內容,可使用 linecache.getline(path, line_number)。它會以文字形式傳回該行,並在原行有換行字元時一併保留。若指定的行不存在,結果會是空字串。linecache 會快取檔案內容以供重複使用;這在多次查詢同一檔案時很方便,但快取資料仍會占用記憶體。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import linecache
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as folder:
path = Path(folder) / "report.txt"
path.write_text("header\nalpha\nbeta\n", encoding="utf-8")
line = linecache.getline(str(path), 2)
print(line.rstrip("\n"))
linecache.clearcache()
範例最後明確呼叫 clearcache(),以釋放快取項目。若檔案內容會變動,就要留意快取是否仍是最新資料;當程式已修改檔案並需要捨棄舊快取時,請在再次查詢行內容前清除快取。
處理行範圍、不存在的行與記憶體限制
若檔案大小適中,而且直接存取比保留整份內容的記憶體成本更重要,請選用 readlines()。若要逐步處理大型檔案,或在找到指定行後停止,請選用 enumerate();但要讀取較後面的目標行,仍須先讀過前面的行。若可接受快取占用記憶體,重複查詢行號時可選用 linecache。這些方法都無法取得超出檔案結尾的行:清單索引會引發 IndexError,逐行走訪則找不到符合項目,而 getline() 會傳回空字串。請先驗證指定行號,或依程式需求處理這些結果。
請以讀取模式開啟文字檔,並盡量使用 with 陳述式,讓檔案在區塊結束時關閉。若已知檔案的編碼,請明確指定。隨著行數與每行長度增加,載入整個檔案可能耗用大量記憶體;不存在適用於所有機器和工作負載的通用檔案大小門檻。串流讀取能限制讀取迴圈保留的行數,但你另外收集的指定行仍會占用記憶體。選擇方法時,應以存取模式和可用記憶體為依據,而不是固定的大小或速度說法。