iT邦幫忙

4

【python內建模組- os/shutil】用python大量處理電腦上的檔案

python中有好用的os模組及shutil模組,
可以用做大量的複製檔案、移動檔案,
亦可大量的修改檔名,
讓我們來看看這兩個模組該如何使用吧。

動機說明

之前在【電腦程式與生活】(1) (2020年2月更新) 以python3下載youtube影片中教過如何用python將youtube影片下載為mp4檔案,
為了方便整理檔案,
我們可能會想要按順序為檔案編號,
或是將資料夾底下的所有檔案名稱印出來,
方便製作音樂清單的目錄。

匯入模組

欲使用python的osshutil模組,需加入這兩行程式碼:

import os
import shutil

os模組使用教學

一、刪除單個檔案

注意被刪除的檔案需存在,
否則程式會報錯。

## 範例寫法
os.remove("1.txt")

二、修改單個檔案名稱

語法: os.rename(A, B),將檔案A重新命名為B,
檔案A必需存在,
否則程式會報錯。

## 範例寫法
os.rename("old.txt", "new.txt")

三、新增資料夾(單層目錄)

注意要建立的資料夾必須不存在,
否則程式會報錯。

## 範例寫法
os.mkdir("./music")
os.mkdir("./music/sub") # 如果前一層資料夾不存在會報錯

四、判斷單層資料夾是否存在,如果不存在就建立

## 範例寫法
path = "./music"
if not os.path.isdir(des_path):  #如果資料夾不存在就建立
    os.mkdir(des_path)

五、新增資料夾(多層目錄)

可設定參數exist_ok =True
預設exist_ok的值是False
意思是若建立的資料夾不存在程式會報錯。

可創建多層的資料夾,如果前一層資料夾不存在,
程式會自動幫你建立。

## 範例寫法
os.makedirs("./music/subdir")
os.makedirs("./music/a/b")
os.makedirs("./music/a/b", exist_ok =True)

六、批量修改檔名

def batch_rename(path, prefix):
    # 函數功能: 在指定path路徑下,將該層檔案及資料夾名稱前加上prefix字串
    for fname in os.listdir(path):
        new_fname = prefix+fname
        os.rename(os.path.join(path, fname), os.path.join(path, new_fname))

七、批量顯示檔名

def batch_showname(path):
    # 函數功能: 顯示指定路徑下,該層的檔案及資料夾名稱
    for fname in os.listdir(path):
        print(os.path.join(path, fname))

八、遞迴顯示所有檔名

def find_dir(path):
    # 函數功能: 遞迴顯示指定路徑下的所有檔案及資料夾名稱
    for fd in os.listdir(path):
        full_path=os.path.join(path,fd)
        if os.path.isdir(full_path):
            print('資料夾:',full_path)
            find_dir(full_path)
        else:
            print('檔案:',full_path)

應用: 顯示整個資料夾下的歌單並重新命名

假設我將python程式命名為renameFileName.py
並在同一個資料夾放入之前載好的歌曲,如圖示:

https://ithelp.ithome.com.tw/upload/images/20200123/20117114xLnGtxWTLn.png

我將歌曲(.mp4)檔存分別存放在資料夾「歌單1」、「歌單2」、「歌單3」中,
則我可以用底下的程式查看現在這個資料夾底下的所有檔案:

import os
def find_dir(path):
    # 函數功能: 遞迴顯示指定路徑下的所有檔案及資料夾名稱
    for fd in os.listdir(path):
        full_path=os.path.join(path,fd)
        if os.path.isdir(full_path):
            print('資料夾:',full_path)
            find_dir(full_path)
        else:
            print('檔案:',full_path)
            
path="./" #指向當前資料夾的路徑
find_dir(path)

假設我們想把歌單1的檔名前全部加上a
把歌單2的檔名前全部加上b
把歌單3的檔名前全部加上c
(方便之後將檔案放在同一個資料夾做排序)
則我們可以這樣寫:

import os
def batch_rename(path, prefix):
    # 函數功能: 在指定path路徑下,將該層檔案及資料夾名稱前加上prefix字串
    for fname in os.listdir(path):
        new_fname = prefix+fname
        os.rename(os.path.join(path, fname), os.path.join(path, new_fname))

batch_rename("./歌單1",'a')
batch_rename("./歌單2",'b')
batch_rename("./歌單3",'c')

shutil模組使用教學

一、複製資料夾內的所有檔案至另一資料夾

語法: shutil.copytree(A, B),將資料夾A底下的所有檔案複製到資料夾B,
shutil.copytree會自動生成資料夾B,
如果資料夾B已經存在程式會報錯。

## 範例寫法
shutil.copytree('./music', './new_dir')

二、刪除一個資料夾及其底下的檔案

## 範例寫法
shutil.rmtree('./music')

三、複製一個檔案(同一個目錄下)

## 範例寫法
shutil.copyfile("old.txt", "new.txt")

四、移動一個目錄或檔案

語法: shutil.move(A, B)
A可以是檔案或是資料夾,

  • 若B是一個已存在的資料夾,將A整個移動到B底下
  • 若B是一個已存在的檔案且A是檔案,則將A覆寫為B
  • 若B不存在,會將A更名為B
## 範例寫法
shutil.move("1.txt", "./a") #將檔案1.txt移動至資料夾a底下
shutil.move("./1", "./a") #將資料夾1整個搬進資料夾a底下

應用: 將整個資料夾下的歌單重新命名並搬至新的資料夾中

假設我將python程式命名為renameFileName.py
並在同一個資料夾放入之前載好的歌曲,如圖示:

https://ithelp.ithome.com.tw/upload/images/20200123/20117114xLnGtxWTLn.png

我將歌曲(.mp4)檔存分別存放在資料夾「歌單1」、「歌單2」、「歌單3」中,
假設我們想把歌單1的檔名前全部加上a
把歌單2的檔名前全部加上b
把歌單3的檔名前全部加上c
並且將這些檔案全數移動至新的資料夾music中,
則我們可以這樣寫:

import os
import shutil
def batch_move_and_rename(src_path, des_path, prefix):
    # 函數功能: 在src_path路徑下,將該層檔案及資料夾名稱前加上prefix字串,並移至路徑des_path
    for fname in os.listdir(src_path):
        new_fname = prefix+fname
        os.rename(os.path.join(src_path, fname), os.path.join(src_path, new_fname))
        shutil.move(os.path.join(src_path, new_fname), des_path)
        
path="./"
des_path = "./music"

batch_move_and_rename("./歌單1",des_path, 'a')
batch_move_and_rename("./歌單2",des_path, 'b')
batch_move_and_rename("./歌單3",des_path, 'c')

這邊需注意若是一開始忘記創建資料夾music
則會將原來的音樂檔更名為music(無副檔名),如圖:
(顯然這不是我們要的效果)

https://ithelp.ithome.com.tw/upload/images/20200208/20117114isJWljnyTK.png

因此建議在程式加入「若資料夾不存在就建立」的判斷,
更正後的程式如下:

import os
import shutil
def batch_move_and_rename(src_path, des_path, prefix):
    # 函數功能: 在src_path路徑下,將該層檔案及資料夾名稱前加上prefix字串,並移至路徑des_path
    for fname in os.listdir(src_path):
        new_fname = prefix+fname
        os.rename(os.path.join(src_path, fname), os.path.join(src_path, new_fname))
        shutil.move(os.path.join(src_path, new_fname), des_path)
        
path="./"
des_path = "./music"
if not os.path.isdir(des_path):  #如果資料夾不存在就建立
    os.mkdir(des_path)

batch_move_and_rename("./歌單1",des_path, 'a')
batch_move_and_rename("./歌單2",des_path, 'b')
batch_move_and_rename("./歌單3",des_path, 'c')

2 則留言

2
Yanwei Liu
iT邦新手 5 級 ‧ 2020-02-11 09:54:38

您好:

在shutil模組使用教學的範例四、移動一個目錄或檔案

範例程式似乎有錯誤
shutil.copyfile("1.txt", "./a") #將檔案1.txt移動至資料夾a底下
shutil.copyfile("./1", "./a") #將資料夾1整個搬進資料夾a底下

應該要改成:
shutil.move("1.txt", "./a") #將檔案1.txt移動至資料夾a底下
shutil.move("./1", "./a") #將資料夾1整個搬進資料夾a底下

心原一馬 iT邦研究生 5 級 ‧ 2020-02-11 13:11:16 檢舉

哈囉,謝謝您的細心,
小馬不慎筆誤寫錯了,
感謝更正/images/emoticon/emoticon41.gif

已於文章內更正囉

很喜歡您的文章 受益良多~

1
intefish
iT邦新手 3 級 ‧ 2020-02-22 09:24:23

版大你好,

第一段改名是否範例有錯

範例寫法

os.remove("old.txt", "new.txt")

心原一馬 iT邦研究生 5 級 ‧ 2020-02-22 10:52:09 檢舉

您好,感謝更正,是我筆誤寫錯了,
已於文章中更正
/images/emoticon/emoticon41.gif/images/emoticon/emoticon41.gif

我要留言

立即登入留言