要在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中的另外兩個變量root
和dirs
的結果如下:
>>> 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']