
程式執行時,變數儲存在記憶體 (RAM) 中,一旦程式結束或電腦關機,資料就會消失。為了持久化 (Persist) 數據,我們需要將資料寫入硬碟中的檔案。
本章將教您如何使用 Python 高效且安全地進行檔案輸入與輸出 (I/O),並介紹現代 Python 開發者必備的 pathlib 模組。
1. 傳統 vs 現代:開啟檔案的方式
1.1 傳統方式 (不推薦)
使用 open() 開啟檔案後,必須記得呼叫 close()。如果中間程式發生錯誤崩潰,close() 可能不會被執行,導致資源洩漏 (Resource Leak),甚至鎖死檔案。
f = open('data.txt', 'w')
try:
f.write('Hello, World!')
finally:
f.close() # 手動關閉,非常麻煩且容易忘記
1.2 推薦方式:Context Managers (with 語句)
使用 with 語句,Python 會在離開區塊時自動關閉檔案,即使發生異常也不例外。這是最 Pythonic 的寫法。
# 檔案會自動安全關閉,不用手寫 close()
with open('data.txt', 'w') as f:
f.write('Hello, Python!')
2. 檔案模式 (File Modes)
open() 函數的第二個參數決定了開啟模式:
| 模式 | 描述 | 注意事項 |
|---|---|---|
'r' | 唯讀 (Read) | 預設模式。若檔案不存在會拋出 FileNotFoundError。 |
'w' | 寫入 (Write) | 若檔案存在會直接覆蓋 (清空舊內容)!若不存在則建立。 |
'a' | 追加 (Append) | 寫入資料到檔案末尾,不會覆蓋舊內容。 |
'b' | 二進制 (Binary) | 用於非文字檔案 (圖片、影片),如 'rb', 'wb'。 |
'x' | 獨佔建立 (Create) | 若檔案已存在會報錯,確保不會意外覆蓋。 |
3. 讀取檔案的技巧
假設我們有一個 poems.txt:
Line 1: 玫瑰是紅的
Line 2: 這裡很冷
Line 3: Python 很酷
3.1 一次讀取全部 (read)
適合小型檔案。
with open('poems.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(content)
3.2 逐行讀取 (readline vs 迭代)
處理大型檔案 (如 10GB 的 log) 時,千萬不能用 read(),否則記憶體會爆掉。
# 方法 A: 使用 for loop (最推薦!記憶體效率最高)
with open('big_log_file.log', 'r', encoding='utf-8') as f:
for line in f:
print(line.strip()) # strip() 去除每行末尾的換行符號
# 方法 B: readlines() (會將所有行讀入 list,記憶體消耗大,僅適合小檔案)
with open('poems.txt', 'r') as f:
lines = f.readlines()
print(lines) # ['Line 1...\n', 'Line 2...\n', ...]
4. 現代路徑處理:pathlib
在 Python 3.4 之前,我們用 os.path 處理路徑,字串拼接容易出錯 (Windows用 \,Linux用 /)。pathlib 提供了物件導向的路徑操作,是現代標準。
from pathlib import Path
# 1. 定義路徑 (跨平台相容)
folder = Path("data") / "subfolder" # 使用 / 運算符拼接路徑!
file_path = folder / "report.txt"
# 2. 建立目錄 (如果不存在)
folder.mkdir(parents=True, exist_ok=True)
# 3. 寫入文字 (快速寫法)
file_path.write_text("這是 pathlib 的寫入測試", encoding='utf-8')
# 4. 讀取文字 (快速寫法)
content = file_path.read_text(encoding='utf-8')
print(content)
# 5. 檢查屬性
print(f"檔案名稱: {file_path.name}")
print(f"副檔名: {file_path.suffix}")
print(f"是否存在: {file_path.exists()}")
5. 處理結構化資料 (CSV & JSON)
5.1 JSON 操作
JSON 是網路資料交換的標準。
import json
data = {"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
# 寫入 JSON 檔案
with open('users.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# 讀取 JSON 檔案
with open('users.json', 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
print(loaded_data['users'][0]['name']) # Alice
5.2 CSV 操作
CSV (Comma-Separated Values) 常見於試算表資料。
import csv
# 寫入 CSV
rows = [
["ID", "Name", "Score"],
[1, "Alice", 95],
[2, "Bob", 80]
]
with open('scores.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerows(rows)
# 讀取 CSV
with open('scores.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f) # 將每行轉為 Dictionary
for row in reader:
print(f"{row['Name']} 得分: {row['Score']}")
6. 總結
檔案操作是程式與外部世界交換數據的基石。
本章重點回顧:
- Context Manager: 永遠使用
with open(...)來確保資源釋放。 - Encoding: 處理中文務必指定
encoding='utf-8'(Windows 預設可能是 cp950)。 - Iterate File: 讀取大檔案時,使用
for line in f:逐行處理。 - pathlib: 使用
Path物件取代舊式的os.path字串操作。 - Structure Data: 善用
json和csv模組處理結構化資料。
下一章,我們將進入程式設計的重頭戲——物件導向程式設計 (Object-Oriented Programming),學習如何設計更模組化、可擴展的程式架構!
延伸閱讀: