前言

os模組雖然可以建立目錄 (mkdir)、刪除檔案 (remove)、刪除空目錄 (rmdir),但沒有提供複製檔案的功能,而且os.rmdir()只能刪除空目錄。

shutil(shell utilities)是一個可跨平台的檔案處理模組,它提供的函式可以在 Python 程式中執行檔案或目錄的複製、刪除或搬移。首先必須匯入shutil模組:

import shutil

常用函式

函式說明
copy(來源檔案, 目的檔案)複製來源檔案及其權限到目的檔案。
copyfile(來源檔案, 目的檔案)複製來源檔案到目的檔案。
copytree(來源目錄, 目的目錄)將來源目錄及其中所有檔案新增到目的目錄。
rmtree(目錄)刪除指定目錄及其中所有檔案。
move(來源檔案或目錄, 目的地)將來源檔案或目錄搬移到目的地。

os的函式相比較,shutil提供更強的處理能力,而且可以跨平台

copy 和 copyfile 函式

copycopyfile函式都可以複製來源檔案到指定的目的檔案,執行時必須確定來源檔案已存在

[簡例] 複製<shutil.py><newfile.py><D:\new.py>檔。(檔名:shutil.py

copy 與 copyfile 的差別

copy()copyfile()
複製內容
複製權限(唯讀等屬性)
目的地可給目錄✅ 自動用原檔名❌ 必須給完整檔名
shutil.copy("a.txt", "backup")           # ✅ 會變成 backup\a.txt
shutil.copyfile("a.txt", "backup")       # ❌ 會被當成要建立名為 backup 的檔案

不確定要用哪個就用 copy()

copy()比較「聰明」,目的地給目錄或檔名都可以,而且會保留檔案權限。
只有在明確不想帶走權限時才用copyfile()

copytree 函式

copytreecopy相似,但它複製的是目錄,複製時來源目錄底下的子目錄和檔案也會被複製,執行時必須確定來源目錄已存在。

[簡例] 複製目前路徑下的<oswalk>目錄到<D:\newoswalk>目錄。(檔名:copytree.py

目的目錄「必須不存在」

copytree()預設會自己建立目的目錄,如果該目錄已經存在,會產生FileExistsError
若要允許覆蓋既有目錄,可加上參數:

shutil.copytree("oswalk", "D:\\newoswalk", dirs_exist_ok=True)

rmtree 函式

os模組的rmdir只能刪除空的目錄,而rmtree則可以刪除指定目錄及目錄底下的子目錄和檔案,執行時必須確定要刪除的目錄已存在。

[簡例] 刪除<D:\newoswalk>目錄。(檔名:rmtree.py

實測os.rmdir()刪除非空目錄的結果:

OSError: [WinError 145] 目錄不是空的。: 'd1'

改用shutil.rmtree()則可以成功刪除。

⚠️ rmtree() 是不可復原的

它會把整個目錄連同所有子目錄、檔案全部刪除,而且不會進資源回收桶
使用前務必:

  1. 先用os.path.exists()確認路徑正確
  2. 路徑變數千萬不要拼錯(例如不小心變成"C:\\"
  3. 重要操作前先加上確認提示
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()可以執行copydel等系統命令來達到相同效果,但那些命令是 Windows 專用的,換到 Linux/macOS 就會失效。
shutil是跨平台的,同一份程式在哪個作業系統都能執行 —— 這是實務上優先選它的主要原因。


相關主題與延伸閱讀