前言
os模組雖然可以建立目錄 (mkdir)、刪除檔案 (remove)、刪除空目錄 (rmdir),但沒有提供複製檔案的功能,而且os.rmdir()只能刪除空目錄。
shutil(shell utilities)是一個可跨平台的檔案處理模組,它提供的函式可以在 Python 程式中執行檔案或目錄的複製、刪除或搬移。首先必須匯入shutil模組:
import shutil常用函式
| 函式 | 說明 |
|---|---|
copy(來源檔案, 目的檔案) | 複製來源檔案及其權限到目的檔案。 |
copyfile(來源檔案, 目的檔案) | 複製來源檔案到目的檔案。 |
copytree(來源目錄, 目的目錄) | 將來源目錄及其中所有檔案新增到目的目錄。 |
rmtree(目錄) | 刪除指定目錄及其中所有檔案。 |
move(來源檔案或目錄, 目的地) | 將來源檔案或目錄搬移到目的地。 |
和os的函式相比較,shutil提供更強的處理能力,而且可以跨平台。
copy 和 copyfile 函式
copy和copyfile函式都可以複製來源檔案到指定的目的檔案,執行時必須確定來源檔案已存在。
[簡例] 複製<shutil.py>為<newfile.py>及<D:\new.py>檔。(檔名:shutil.py)
程式碼:
shutil.pyimport os, shutil cur_path = os.path.dirname(__file__) # 取得目前路徑 destfile = cur_path + "\\" + "newfile.py" shutil.copy("shutil.py", destfile) # 檔案複製 shutil.copyfile("shutil.py", "D:\\new.py") # 檔案複製
copy 與 copyfile 的差別
copy() | copyfile() | |
|---|---|---|
| 複製內容 | ✅ | ✅ |
| 複製權限(唯讀等屬性) | ✅ | ❌ |
| 目的地可給目錄 | ✅ 自動用原檔名 | ❌ 必須給完整檔名 |
shutil.copy("a.txt", "backup") # ✅ 會變成 backup\a.txt
shutil.copyfile("a.txt", "backup") # ❌ 會被當成要建立名為 backup 的檔案不確定要用哪個就用
copy()
copy()比較「聰明」,目的地給目錄或檔名都可以,而且會保留檔案權限。
只有在明確不想帶走權限時才用copyfile()。
copytree 函式
copytree和copy相似,但它複製的是目錄,複製時來源目錄底下的子目錄和檔案也會被複製,執行時必須確定來源目錄已存在。
[簡例] 複製目前路徑下的<oswalk>目錄到<D:\newoswalk>目錄。(檔名:copytree.py)
程式碼:
copytree.pyimport shutil shutil.copytree("oswalk", "D:\\newoswalk") # 目錄複製
目的目錄「必須不存在」
copytree()預設會自己建立目的目錄,如果該目錄已經存在,會產生FileExistsError。
若要允許覆蓋既有目錄,可加上參數:shutil.copytree("oswalk", "D:\\newoswalk", dirs_exist_ok=True)
rmtree 函式
os模組的rmdir只能刪除空的目錄,而rmtree則可以刪除指定目錄及目錄底下的子目錄和檔案,執行時必須確定要刪除的目錄已存在。
[簡例] 刪除<D:\newoswalk>目錄。(檔名:rmtree.py)
程式碼:
rmtree.pyimport shutil shutil.rmtree("D:\\newoswalk") # 刪除目錄
實測os.rmdir()刪除非空目錄的結果:
OSError: [WinError 145] 目錄不是空的。: 'd1'改用shutil.rmtree()則可以成功刪除。
⚠️
rmtree()是不可復原的它會把整個目錄連同所有子目錄、檔案全部刪除,而且不會進資源回收桶。
使用前務必:
- 先用
os.path.exists()確認路徑正確- 路徑變數千萬不要拼錯(例如不小心變成
"C:\\")- 重要操作前先加上確認提示
import os, shutil target = "D:\\newoswalk" if os.path.exists(target): if input(f"確定要刪除 {target} 及其所有內容?(y/N) ") == "y": shutil.rmtree(target)
move 函式
move可以將檔案或目錄搬移到目的地。搬移與複製的差別在於:搬移後來源會消失。
import shutil
shutil.move("old.txt", "backup\\new.txt") # 搬移並改名
shutil.move("oldDir", "D:\\newDir") # 搬移整個目錄
move()也可以用來「改名」在同一個目錄內搬移,效果就等於改名:
shutil.move("a.txt", "b.txt") # 等同改名
os模組也有專門的os.rename("a.txt", "b.txt")可以做同樣的事。
os 與 shutil 的功能對照
| 需求 | os 模組 | shutil 模組 |
|---|---|---|
| 建立目錄 | os.mkdir() | — |
| 刪除檔案 | os.remove() | — |
| 刪除空目錄 | os.rmdir() | — |
| 刪除非空目錄 | ❌ 做不到 | shutil.rmtree() |
| 複製檔案 | ❌ 做不到 | shutil.copy() |
| 複製整個目錄 | ❌ 做不到 | shutil.copytree() |
| 搬移/改名 | os.rename() | shutil.move() |
| 執行系統命令 | os.system() | — |
為什麼不要用
os.system("copy ...")2. 資料夾的建立與刪除 提到
os.system()可以執行copy、del等系統命令來達到相同效果,但那些命令是 Windows 專用的,換到 Linux/macOS 就會失效。
shutil是跨平台的,同一份程式在哪個作業系統都能執行 —— 這是實務上優先選它的主要原因。
相關主題與延伸閱讀
- 0. 章節索引:本章全部筆記的學習地圖與快速查找。
- 2. 資料夾的建立與刪除:
os模組的mkdir()、rmdir()、remove()。 - 6. os.path 路徑處理:組合來源與目的地的完整路徑。
- 7. os.walk 與 glob 目錄走訪:先找出要複製或搬移的檔案清單。
- 5. 例外處理:來源不存在、目的地已存在、權限不足時的防呆處理。