Python 檔案操作:資料持久化的關鍵 (第 8 章)

站主自己的課程,請大家支持
揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站? 揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站?
  • Post by
  • Dec 22, 2023
post-thumb

程式執行時,變數儲存在記憶體 (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: 善用 jsoncsv 模組處理結構化資料。

下一章,我們將進入程式設計的重頭戲——物件導向程式設計 (Object-Oriented Programming),學習如何設計更模組化、可擴展的程式架構!


延伸閱讀

LATEST POST
TAG