前言
前面介紹的函式都是針對單一檔案或單一目錄。但實務上常常需要「把某個資料夾底下所有檔案都處理一遍」,這時就需要能夠走訪整棵目錄樹的工具。
本節介紹兩個常用的作法:
| 模組 | 用途 | 適合情境 |
|---|---|---|
os.walk | 遞迴走訪目錄及所有子目錄 | 要處理整棵目錄樹 |
glob | 以萬用字元取得符合條件的檔案串列 | 只要挑出特定類型的檔案 |
os.walk 函式
os.walk可以搜尋指定目錄以及其子目錄,它會傳回一個包含 3 個元素的元組,分別是:
| 元素 | 內容 |
|---|---|
dirname | 目前所在的目錄名稱(字串) |
subdir | 下一層的目錄串列(list) |
files | 目前目錄中所有的檔案串列(list) |
由於它具有類似遞迴方式的處理能力,可以遍歷所有的子目錄,功能非常強大。
範例目錄結構
為了方便說明,假設有下列的目錄結構:
\oswalk
├─\Dir ──────── \SubDir ──── SubDir1.txt
│ ├─ Dir1.txt
│ └─ Dir2.txt
├─ oswalk.py
└─ oswalk1.txt
[結果]
檔案路徑: C:\example\ch09\oswalk
目錄串列: ['Dir']
檔案串列: ['oswalk.py', 'oswalk1.txt']
檔案路徑: C:\example\ch09\oswalk\Dir
目錄串列: ['SubDir']
檔案串列: ['Dir1.txt', 'Dir2.txt']
檔案路徑: C:\example\ch09\oswalk\Dir\SubDir
目錄串列: []
檔案串列: ['SubDir1.txt']程式碼:
oswalk.pyimport os cur_path = os.path.dirname(__file__) # 取得目前路徑 sample_tree = os.walk(cur_path) for dirname, subdir, files in sample_tree: print("檔案路徑:", dirname) print("目錄串列:", subdir) print("檔案串列:", files) print()
說明
os.walk()每繞一圈就回傳一層目錄的資訊,因此用for迴圈接收。- 一次解包成三個變數
dirname, subdir, files,對應前面表格的三個元素。- 首先取得的是最上層
<oswalk>,該路徑包含一個<Dir>目錄以及兩個檔案。- 接著進入子目錄
<Dir>,其下包含<SubDir>目錄和兩個 txt 檔。- 最後進入
<SubDir>,該目錄串列為[]表示已無子目錄。
走訪順序是「由上而下、逐層深入」
os.walk預設是先處理上層目錄,再往下鑽。每一圈只回傳「當層」的資訊,子目錄的內容要等下一圈才會出現。
觀察上面的結果:Dir1.txt並沒有出現在第一圈,而是等走到\Dir那一層才出現。
取得每個檔案的完整路徑
files裡面只有檔名,沒有路徑。要組合成完整路徑,必須搭配 6. os.path 路徑處理 的join():
import os
for dirname, subdir, files in os.walk("."):
for f in files:
fullpath = os.path.join(dirname, f) # ⭐ 組合完整路徑
print(fullpath, os.path.getsize(fullpath), "bytes")常見錯誤:直接用檔名去開檔
for dirname, subdir, files in os.walk(path): for f in files: open(f) # ❌ 找不到檔案!f 只是檔名,沒有路徑 open(os.path.join(dirname, f)) # ✅只有當程式剛好在該目錄執行時前者才會成功,一旦走進子目錄就會失敗。
glob 模組
glob可以取得符合指定條件的檔案串列,語法比os.walk簡單得多。
import glob
glob.glob("路徑名稱")路徑名稱可以明確指定檔案名稱,也可使用「*」萬用字元。
[簡例] 取得<glob.py>檔、檔名前兩個字元是os開頭的所有 py 檔案,以及所有副檔名為 txt 的檔案。(檔名:glob.py)
[結果]
glob.py
osdirname.py
osexists.py
osgetcwd.py
osmkdir.py
ospath.py
osremove.py
osrmdir.py
ossystem.py
file1.txt
file2.txt
fileUTF8.txt
password.txt
test01.txt
test02.txt程式碼:
glob.pyimport glob files = glob.glob("glob.py") + glob.glob("os*.py") + glob.glob("*.txt") for file in files: print(file)
萬用字元
| 萬用字元 | 意義 | 範例 |
|---|---|---|
* | 任意長度(含 0 個)的字元 | *.txt 所有 txt 檔 |
? | 剛好一個字元 | file?.txt file1.txt、file2.txt |
[…] | 中括號內任一字元 | file[12].txt 只有 file1、file2 |
遞迴搜尋子目錄:
recursive=True書上沒有提到,但
glob其實也能像os.walk一樣往下鑽,只要用**並加上recursive=True:import glob glob.glob("**/*.txt", recursive=True) # 所有子目錄中的 txt 檔這是
glob最實用的功能之一,只要一行就能取代整段os.walk。
兩者的選用
os.walk | glob | |
|---|---|---|
| 寫法 | 需要for迴圈解包三個變數 | 一行取得串列 |
| 回傳 | 目錄與檔名分開 | 直接是路徑串列 |
| 篩選條件 | 要自己寫if判斷 | 用萬用字元直接篩 |
| 取得目錄結構 | ✅ 知道每個檔案在哪一層 | ❌ 只有路徑字串 |
| 適合 | 需要知道目錄層次、要對目錄本身做事 | 只想挑出特定檔案 |
簡單說:只是要找檔案 → 用
glob;需要處理目錄結構 → 用os.walk。
相關主題與延伸閱讀
- 0. 章節索引:本章全部筆記的學習地圖與快速查找。
- 6. os.path 路徑處理:走訪時必須用
join()組合完整路徑。 - 2. 資料夾的建立與刪除:
os模組的基本目錄操作。 - 8. shutil 檔案與目錄的複製搬移:找到檔案後進行複製或搬移。
- 4. 文字檔資料的寫入與讀取:走訪到的檔案要如何讀取內容。
- 5. 例外處理:走訪過程中遇到權限不足等錯誤時的處理。