讀寫檔案與整理資料夾
學會用 Python 讀寫文字檔、列出資料夾裡的檔案,並寫出一支「先預覽、再執行」的批次改檔名腳本。
為什麼從檔案開始?
自動化的第一步,幾乎都跟檔案有關:整理下載資料夾、把掃描的發票照片改成有規則的名字、把每天的紀錄寫進文字檔。這些事手動做一次不難,但每週做、每次幾十個檔案,就很耗時間,也容易出錯。
如果你上過「Python 第一步」,其實已經寫過讀寫檔案的程式了:記帳小工具裡的 with FILE.open(...) 就是。這堂課把它講完整,再加上「整理資料夾」的能力。
先搞懂「路徑」
路徑就是檔案的地址。有兩種寫法:
- 絕對路徑:從磁碟最上層開始寫,例如 Windows 的
C:\Users\amy\Documents\notes.txt,或 macOS 的/Users/amy/Documents/notes.txt。 - 相對路徑:從「終端機目前所在的資料夾」開始算,例如
notes.txt或發票掃描/IMG_0001.jpg。
新手最常遇到的 FileNotFoundError,多半是因為終端機站的位置和你以為的不一樣。還記得「Python 第一步」說過的嗎?用 VS Code 開啟資料夾,再用內建終端機執行,就不容易出錯。
讀寫文字檔
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("今天要繳電話費\n")
with open("notes.txt", "a", encoding="utf-8") as f:
f.write("記得買牛奶\n")
with open("notes.txt", encoding="utf-8") as f:
for line in f:
print(line.strip())
今天要繳電話費
記得買牛奶
with 會在縮排裡的程式跑完後自動關檔。.strip() 把每行頭尾的換行和空白去掉,印出來才不會多空一行。
第二個參數是開檔模式,選錯了後果差很多:
w 會先把檔案清空。想「追加」一行,要用 a。
用 pathlib 處理資料夾
pathlib 是 Python 內建的工具,用 Path 物件代表一個路徑。它的好處是同一份程式在 Windows 和 macOS 上都能跑,不用煩惱斜線方向。
from pathlib import Path
folder = Path("發票掃描")
print(folder.exists())
for p in folder.glob("*.jpg"):
print(p.name, p.suffix, p.stat().st_size)
backup = Path("備份")
backup.mkdir(exist_ok=True)
print(backup / "2026-11.txt")
| 寫法 | 用途 |
|---|---|
folder.glob("*.jpg") |
找出資料夾裡所有 jpg 檔,* 代表「任何名字」 |
p.name、p.stem、p.suffix |
完整檔名、不含副檔名的名字、副檔名 |
folder / "a.txt" |
組合路徑,自動用對的斜線 |
mkdir(exist_ok=True) |
建立資料夾,已經存在也不會報錯 |
p.rename(new_path) |
改名或搬移檔案 |
實戰:批次改檔名
情境:你用手機掃描了一疊發票,檔名是 IMG_0001.jpg、IMG_0002.jpg……想改成 2026-11_發票_001.jpg 這種一看就懂的名字。
第一步:做一份假資料來練習
不要直接拿真的照片來試。 先用程式產生幾個假檔案:
from pathlib import Path
folder = Path("發票掃描")
folder.mkdir(exist_ok=True)
for n in range(1, 6):
(folder / f"IMG_{n:04d}.jpg").write_text("測試用", encoding="utf-8")
f"IMG_{n:04d}.jpg" 裡的 :04d 是「補零到 4 位數」,所以 1 會變成 0001。
第二步:先預覽,確認沒問題再執行
from pathlib import Path
folder = Path("發票掃描")
DRY_RUN = True # True=只預覽;確認沒問題後才改成 False
files = sorted(folder.glob("IMG_*.jpg"))
for i, old in enumerate(files, start=1):
new = old.with_name(f"2026-11_發票_{i:03d}.jpg")
if new.exists():
print(f"跳過:{new.name} 已經存在")
continue
print(f"{old.name} → {new.name}")
if not DRY_RUN:
old.rename(new)
IMG_0001.jpg → 2026-11_發票_001.jpg
IMG_0002.jpg → 2026-11_發票_002.jpg
IMG_0003.jpg → 2026-11_發票_003.jpg
IMG_0004.jpg → 2026-11_發票_004.jpg
IMG_0005.jpg → 2026-11_發票_005.jpg
幾個重點:
enumerate(files, start=1)同時給你「第幾個」和「那個檔案」,從 1 開始數。sorted()讓順序固定,不然每次跑的順序可能不同。with_name()保留原本的資料夾,只換檔名。- 檢查
new.exists()是為了不覆蓋到已有的檔案。在 macOS 和 Linux 上,rename遇到同名檔案會直接覆蓋、不會警告(Windows 則會報錯)。continue會跳過這一圈,直接處理下一個。
確認預覽的結果正確,把 DRY_RUN 改成 False 再跑一次,檔案才會真的改名。
讓 AI 幫你寫,但要求它加上安全機制
批次處理檔案的腳本,AI 寫得又快又好。差別在於你會不會要求它「安全地」寫。
請幫我寫一支 Python 腳本,用 pathlib 把「下載」資料夾裡的檔案依副檔名分類,移到對應的子資料夾(例如 pdf、jpg、xlsx)。要求:
- 最上面有 DRY_RUN 開關,預設 True,只印出「會怎麼搬」,不真的搬。
- 目標位置已有同名檔案時跳過,並印出提醒。
- 不要刪除任何檔案。
- 每一段加上中文註解,我是初學者。
拿到程式後,先讀過一遍,找到 DRY_RUN 和「同名就跳過」的那幾行,確認 AI 真的有照做。
- 用「第一步」的程式產生 5 個假的
IMG_檔案。 - 執行改名腳本,先看預覽,再改成
DRY_RUN = False真的改名。 - 把腳本再跑一次,觀察會發生什麼事。(提示:
glob("IMG_*.jpg")還找得到檔案嗎?) - 加分題:每次改名時,用
"a"模式把「舊檔名 → 新檔名」寫進rename_log.txt,留下紀錄。
讀完了嗎?
標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。
留言與討論
卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。