Python 的 os 模組提供不少便利的功能讓我們能夠操作檔案/資料夾的路徑、操作等等。直到 Python 3.4 之後提供一個新模組 pathlib,將各種檔案/資料夾相關的操作封裝在 Path 等類別之中,讓檔案/資料夾的操作更加物件導向。

本文將說明與展示 pathlib 模組。

本文環境

  • Python 3.6.5
  • macOS 10.15

Path 類別

pathlib 底下有許多類別可供使用,例如 WindowsPath , PosixPath , PurePath 等等。一般來說,只要使用 Path 類別即可,不需要特意按照不同平台使用不同的類別。

接下來,實際以多個範例介紹如何使用 Path 類別!

檢查檔案或資料夾是否存在

以往檢查檔案是否存在,會用類似以下的程式碼進行檢查:

>>> import os
>>> os.path.exists('/tmp/myfile.txt')

如果改成 Path 類別後,就是以下形式:

>>> from pathlib import Path
>>> path = Path('/tmp/myfile.txt')
>>> path.exists()
False

上述範例可以看到透過 Path 類別所提供的 exists() 方法即可判斷檔案是否存在。整體而言,程式碼閱讀起來也更為簡潔易懂,更加物件導向。

建立檔案

用過 Linux 的人可能都會知道能夠用 touch 指令建立檔案,而 Path 也提供一樣的功能:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.exists()
False
>>> path.touch()
>>> path.exists()
True

上述範例可以看到執行 path.touch() 之後,檔案就被建立起來。

取得檔名 / 副檔名

以往取得檔名、副檔名可以透過 os.path.basename()os.path.splitext() 達成。而 Path 提供 namesuffix 屬性能夠輕鬆取得檔名與副檔名:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.name
myfile.txt
>>>
>>> path.suffix
.txt

寫入 / 讀取檔案

Path 類別也提供 write_text() , read_text() 等方法,讓開發者可以輕鬆地寫入、讀取檔案:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.write_text('Hello')
5
>>> path.write_text('World')
5

值得注意的是,上述範例執行 2 次 write_text() ,檔案內容並不會附加,而是直接覆寫(overwrite) ,因此以下 read_text() 只會讀取到 World:

>>> path.read_text()
'World'

此外, Path 也有支援 with 語法以及 open() 方法:

>>> with path.open('w') as f:
...     f.write('Hello')
5

以往判斷路徑是否為檔案、資料夾、 symbol link 會使用以下程式碼進行判斷:

>>> import os
>>> os.path.isfile('/tmp/myfile.txt')
>>> os.path.isdir('/tmp/myfile.txt')
>>> os.path.islink('/tmp/myfile.txt')

這些常用的方法也被整合至 Path 中:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.touch()
>>> path.is_file()
True
>>> path.is_dir()
False
>>> path.is_symlink()
False

當然,其他還有 is_socket() is_fifo() is_block_device() 等更多方法可以使用。

刪除檔案

正因為 Path 類別整合各種與檔案、資料夾相關的操作,理想當然也能夠呼叫刪除檔案的方法:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.touch()
>>> path.is_file()
True
>>> path.unlink()
>>> path.exists()
False

上述範例在呼叫 unlink() 方法後,檔案就被刪除了。

取得檔案大小

Path 類別也提供 stat() 方法讓開發者可以取得檔案詳細的資訊,例如經常會使用的檔案大小。

我們可以先用以下程式碼建立一個很小的檔案:

>>> from pathlib import Path
>>> path = Path('/tmp', 'myfile.txt')
>>> path.touch()
>>> path.write_text('HelloWorld')
10

接著呼叫 stat() 方法,可以看到 stat() 方法會回傳 os.stat_result ,其中 st_size 就是我們需要的檔案大小:

>>> path.stat()
os.stat_result(st_mode=33188, st_ino=20705682, st_dev=16777224, st_nlink=1, st_uid=501, st_gid=0, st_size=10, st_atime=1602572294, st_mtime=1602572354, st_ctime=1602572354)

因此可以用 path.stat().st_size 直接取得檔案大小 10 bytes:

>>> path.stat().st_size
10

走訪資料夾內的所有檔案與資料夾

另一個經常會用到的需求就是走訪某資料夾內的所有檔案與資料夾,只要呼叫 iterdir() 即可:

>>> from pathlib import Path
>>> for x in Path('/tmp').iterdir():
...     print(type(x), x)
...
<class 'pathlib.PosixPath'> /tmp/com.google...
<class 'pathlib.PosixPath'> /tmp/com.apple...
<class 'pathlib.PosixPath'> /tmp/myfile.txt
<class 'pathlib.PosixPath'> /tmp/...

上述範例值得注意的是 iterdir() 所 yield 的每 1 個元素也是 Parh 類別的實例,因此同樣能夠享用 Path 類別所提供的各種便利功能。

Path 的運算

Path 類別還有 1 個有趣的特性,該類別實例(instance)能夠透過 / 除法運算元進行路徑的合併,例如:

>>> Path('/home') / Path('abc')
PosixPath('/home/abc')

此外也可以 2 個 Path 類別實例之間進行比較:

>>> Path('/tmp') == Path('/tmp')
True
>>> Path('/tmp/a') == Path('/tmp/b')
False

總結

除了前述所提及的功能與範例之外, Path 類別其實還有相當多的便利功能可以使用,有興趣的話,不妨閱讀官方文件。

另外,官方文件也整理出對照 Pathos 模組相關功能的對照表,可以參考 Correspondence to tools in the os module 一表。

References

https://docs.python.org/3/library/pathlib.html