Python中用os.walk()列出資料夾中的全部內容

要在Python中列出某個資料夾中的全部內容,包括子資料夾中的全部內容,我們可用os模組中的walk函數。這個函數的定義:

os.walk(top, topdown=True, onerror=None, followlinks=False)

官方對其用法介紹的第一段寫:

Generate the file names in a directory tree by walking the tree either top-down or bottom-up. For each directory in the tree rooted at directory top (including top itself), it yields a 3-tuple (dirpath, dirnames, filenames).

看到"Generate"和"yield"就知道,這個函數是個generator,所以千萬不能這樣寫:

root, dirs, files = os.walk('mypath')

因為os.walk()本身是個generator object:

>>> import os
>>> os.walk('.')
<generator object walk at 0x7f0bcda92200>

既然如此,我們可以使用next()(也可以直接從generator object調用其__next__方法)來逐層得出資料夾中的內容。例如,現在有如下的資料夾結構:

vivi@ubuntu-xenial:/home/vivi$ tree
├── dir1
│   ├── dir1_file1.txt
│   ├── dir1_file2.txt
│   ├── dir1_file3.txt
│   ├── dir2_1
│   │   ├── dir2_file1.txt
│   │   ├── dir2_file2.txt
│   │   ├── dir3
│   │   │   └── dir3_file1.txt
│   │   └── hello.py
│   └── dir2_2
│       ├── dir2_file3.txt
│       ├── dir2_file4.txt
│       └── world.py

那麼,如果只是要找出dir1資料夾中的內容,可以寫:

>>> import os
>>> walk = os.walk('dir1')
>>> root, dirs, files = next(walk)
>>> files
['dir1_file1.txt', 'dir1_file2.txt', 'dir1_file3.txt']

運用了next()函數,就把os.walk()中的第一層內容yield出來了。這也是generator的好處:不用再算下去了,當有需要時,隨時可以再繼續算下一層,yield出新的結果。另外,上述代碼生成的tuple中的另外兩個變量rootdirs的結果如下:

>>> root
'dir1'
>>> dirs
['dir2_1', 'dir2_2']

如果再用一次next(),那麼就會生成出dir2_1中的內容。此時要注意,如果再next()一次,那麼會生成出dir2_2還是dir3的內容呢?

>>> root, dirs, files = next(walk)
>>> files
['dir2_file1.txt', 'dir2_file2.txt', 'hello.py']
>>> root, dirs, files = next(walk)
>>> files
['dir3_file1.txt']

結果是dir3的內容。所以,如果只要列出最外層資料夾dir1的文檔,只需要寫:

>>> _, _, files = next(os.walk('dir1'))
>>> files
['dir1_file1.txt', 'dir1_file2.txt', 'dir1_file3.txt']

當然,資料夾中的層次少的時候還可以用next()一層層列出結果,既然os.walk()是generator,更好的做法是用for語句把全部內容列出來。

>>> all_files = []
>>> for _, _, files in os.walk('dir1'):
...   all_files += files
...
>>> all_files
['dir1_file1.txt', 'dir1_file2.txt', 'dir1_file3.txt', 'dir2_file1.txt', 'dir2_file2.txt', 'hello.py', 'dir3_file1.txt', 'dir2_file3.txt', 'dir2_file4.txt', 'world.py']

如果不想用next()而又只要列出dir1中的文檔,那麼在for語句的第一次迴圈時,就要用break跳出來:

>>> dir1_files = ''
>>> for _, _, files in os.walk('dir1'):
...   dir1_files = files
...   break
...
>>> dir1_files
['dir1_file1.txt', 'dir1_file2.txt', 'dir1_file3.txt']

os.walk()中的topdown參數默認為True,如果將其設為False,那麼os.walk()將從資料夾的最內層開始生成資料夾內容。例如要列出dir1中最內層資料夾中的文檔,可以寫:

>>> _, _, files = next(os.walk('dir1', topdown=False))
>>> files
['dir3_file1.txt']

最後,如果現在要單獨列出dir1中的某類型檔案,如.py的,可以將os.walk()生成的files這個list拆開,逐一判斷它裏面的文檔名最後是不是'.py'

>>> all_py_files = []
>>> for _, _, files in os.walk('dir1'):
...   all_py_files += [f for f in files if f.lower().endswith('.py')]
...
>>> all_py_files
['hello.py', 'world.py']
4 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments