B2.5 檔案處理
檔案處理(File processing)讓程式能把資料存到硬碟上,程式結束後資料仍然保存,下次再讀回來使用。本頁說明檔案的開啟模式、讀取與寫入文字檔、處理 CSV 格式資料,以及檔案操作時必須注意的錯誤處理。
為什麼程式需要檔案?
變數存在 RAM 中,程式結束就消失。檔案存在次要儲存裝置,屬於 永久儲存(persistent storage),適合儲存設定、使用者資料、紀錄檔,也是 IA 中保存資料最簡單的方式。
檔案開啟模式
| 模式 | Python | 說明 |
|---|---|---|
| 讀取 | "r" |
檔案必須存在,否則產生錯誤 |
| 寫入 | "w" |
建立新檔;檔案已存在會被清空覆寫 |
| 附加 | "a" |
寫到檔案尾端,保留原內容 |
如何讀寫文字檔?
# 寫入:with 區塊結束時自動關閉檔案
with open("scores.txt", "w", encoding="utf-8") as f:
f.write("Amy,6\n")
f.write("Ben,5\n")
# 附加
with open("scores.txt", "a", encoding="utf-8") as f:
f.write("Chris,7\n")
# 逐行讀取
with open("scores.txt", "r", encoding="utf-8") as f:
for line in f:
name, score = line.strip().split(",")
print(name, int(score))
import java.io.*;
// 寫入(第二個參數 true 表示附加模式)
try (PrintWriter out = new PrintWriter(new FileWriter("scores.txt", true))) {
out.println("Amy,6");
out.println("Ben,5");
} catch (IOException e) {
System.out.println("寫入失敗:" + e.getMessage());
}
// 逐行讀取
try (BufferedReader in = new BufferedReader(new FileReader("scores.txt"))) {
String line;
while ((line = in.readLine()) != null) {
String[] parts = line.split(",");
System.out.println(parts[0] + " " + Integer.parseInt(parts[1]));
}
} catch (IOException e) {
System.out.println("讀取失敗:" + e.getMessage());
}
重點:
strip()去除行尾換行字元\n,否則比對字串時會出錯。split(",")把一行切成欄位,讀到的都是字串,需要轉型。- Python 的
with、Java 的 try-with-resources 確保檔案一定會被關閉,避免資料沒寫進去或檔案被鎖住。
如何處理 CSV 檔?
CSV(Comma-Separated Values)用逗號分隔欄位,可以用 Excel 開啟,是交換表格資料最常見的格式。Python 的 csv 模組能正確處理欄位中含有逗號或引號的情況:
import csv
students = [
{"name": "Amy", "level": "HL", "score": 6},
{"name": "Ben", "level": "SL", "score": 5},
]
with open("students.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["name", "level", "score"])
writer.writeheader()
writer.writerows(students)
with open("students.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
if row["level"] == "HL":
print(row["name"], row["score"])
檔案操作會發生哪些錯誤?
- 檔案不存在(Python
FileNotFoundError、JavaFileNotFoundException)。 - 沒有讀寫權限(
PermissionError)。 - 資料格式不符,例如某一行少了逗號或分數不是數字(
ValueError)。
try:
with open("scores.txt", encoding="utf-8") as f:
lines = f.readlines()
except FileNotFoundError:
print("找不到檔案,將建立新檔")
lines = []
推薦影音
Python 檔案物件:讀取與寫入(Corey Schafer)
簡述:Corey Schafer 詳細示範 open() 的各種模式、context manager(with)、read/readline/逐行讀取,以及複製文字檔與圖片檔,是 Python 檔案處理最完整的入門影片之一。
檔案與檔案系統
簡述:Crash Course 說明檔案在磁碟上如何儲存、檔案格式與副檔名的意義,幫助理解程式寫出的檔案實際上是什麼。
練習題
練習 1:開啟模式
一個程式每次執行都要在 log.txt 末端加上一行執行時間,應該用哪種模式?用 "w" 會有什麼問題?
參考答案
用附加模式 "a"。用 "w" 每次開檔都會清空檔案,只會留下最後一次的紀錄。
練習 2:讀檔計算
scores.txt 每行格式為 名字,分數。寫程式讀檔並印出平均分數與最高分學生的名字。
參考答案
best_name, best_score = None, -1
total, count = 0, 0
with open("scores.txt", encoding="utf-8") as f:
for line in f:
name, score = line.strip().split(",")
score = int(score)
total += score
count += 1
if score > best_score:
best_name, best_score = name, score
print("平均:", total / count)
print("最高分:", best_name)
練習 3:處理錯誤資料
修改練習 2,讓程式遇到格式錯誤的行(例如 Amy,six 或空行)時跳過該行並繼續執行。
練習 4:篩選並寫出新檔
讀取 students.csv,把所有分數 ≥ 6 的學生寫到新檔 honours.csv(含標題列)。
參考答案
import csv
with open("students.csv", newline="", encoding="utf-8") as src, \
open("honours.csv", "w", newline="", encoding="utf-8") as dst:
reader = csv.DictReader(src)
writer = csv.DictWriter(dst, fieldnames=reader.fieldnames)
writer.writeheader()
for row in reader:
if int(row["score"]) >= 6:
writer.writerow(row)