Pathlib模塊


Python 文件路徑處理問題

由於許多不同的原因,使用文件和與文件系統交互很重要。 最簡單的情況可能只涉及讀取或寫入文件,但有時候會有更復雜的任務。 也許你需要列出給定類型的目錄中的所有文件,查找給定文件的父目錄,或者創建一個尚不存在的唯一文件名。

一般情況,Python 使用常規文本字符串表示文件路徑。 一般在使用 os,glob 和 shutil 等庫的時候會使用到路徑拼接的操作,使用os模塊拼接起來顯得略顯復雜,以下示例僅需要三個 import 語句來將所有文本文件移動到歸檔目錄:

1 import os
2 import glob
3 import shutil
4 
5 for file_name in glob.glob("*.txt"):
6     new_path = os.path.join('archive', file_name)
7     shutil.move(file_name, new_path)

使用常規的字符串去拼接路徑是可以的,但是由於不同的操作系統使用的分隔符不同,這樣就容易出現問題,所以一般我們使用最多的還是使用 os.path.join()

Python 3.4 中引入了 pathlib 模塊(PEP 428)再一次的優化了路徑的拼接。使用 pathlib 庫的 Path 方法,可以將一個普通的字符串轉換為 pathlib.Path 對象類型的路徑

創建路徑

1 from pathlib import Path

.cwd(當前工作目錄)和 .home(用戶的主目錄):

1 from pathlib import Path
2 
3 now_path = Path.cwd()
4 home_path = Path.home()
5 
6 print("當前目錄", now_path, type(now_path))
7 print("home目錄", home_path, type(home_path))

輸出:

1 當前目錄 C:\Users\huangm\Desktop <class 'pathlib.WindowsPath'>
2 home目錄 C:\Users\huangm <class 'pathlib.WindowsPath'>

可以通過把字符串類型的路徑,轉換為 Pathlib.Path 類型的路徑

1 import pathlib
2 DIR_PATH = pathlib.Path('/Users/huangm/Untitled.ipynb')
3 print(DIR_PATH, type(DIR_PATH))

輸出:

1 \Users\huangm\Untitled.ipynb <class 'pathlib.WindowsPath'>

讀文件和寫文件

open 來操作文件讀寫操作的時候,不僅可以使用字符串格式的路徑,對於 pathlib 生成的路徑完全可以直接使用:

1 import pathlib
2 
3 path = pathlib.Path.cwd() / '123.txt'
4 with open(path, mode='r') as fid:
5     headers = [line.strip() for line in fid if line.startswith('#')]
6 
7 print('\n'.join(headers))

或者在 pathlib 的基礎使用 open,我們推薦使用下面的方式

1 import pathlib
2 
3 DIR_PATH = pathlib.Path("/Users/huangm") / "Desktop" / "123.txt"
4 with DIR_PATH.open('r') as fs:
5     data = fs.read()
6 print(data)

實際上這里的 open 方法,底層也是調用了 os.open 的方法

可以不用再使用 with open 的形式即可以進行讀寫。

1 import pathlib
2 
3 DIR_PATH = pathlib.Path("/Users/huangm") / "Desktop" / "123.txt"
4 print(DIR_PATH.read_text()) #找到對應的路徑然后打開文件,讀成str格式。等同open操作文件的"r"格式。
5 print(DIR_PATH.read_bytes()) #讀取字節流的方式。等同open操作文件的"rb"格式
6 print(DIR_PATH.write_text("妹子")) #文件的寫的操作,等同open操作文件的"w"格式。
7 print(DIR_PATH.write_bytes(b'#\xb4\xb2\xb5\xe6 \xd0\xe8\xd2\xaa 1\r\n\r\n\xc1\xb9\xcf\xaf ')) #文件的寫的操作,等同open操作文件的"wb"格式。

使用 resolve 可以通過傳入文件名,來返回文件的完整路徑,使用方式如下

1 import pathlib
2 text_path = pathlib.Path('123.txt')
3 print(text_path.resolve())

輸出:

1 C:\Users\huangm\Desktop\123.txt

需要注意的是 “123.txt” 文件要和我當前的程序文件在同一級目錄。

選擇路徑的不同組成部分

pathlib 還提供了很多路徑操作的屬性,這些屬性可以選擇路徑的不用部位,如

.name: 可以獲取文件的名字,包含拓展名。
.parent: 返回上級文件夾的名字
.stem: 獲取文件名不包含拓展名
.suffix: 獲取文件的拓展名
.anchor: 類似盤符的一個東西,

1 import pathlib
2 
3 now_path = pathlib.Path.cwd() / '123.txt'
4 print("name", now_path.name)
5 print("stem", now_path.stem)
6 print("suffix", now_path.suffix)
7 print("parent", now_path.parent)
8 print("anchor", now_path.anchor)

輸出:

1 name 123.txt
2 stem 123
3 suffix .txt
4 parent C:\Users\huangm\Desktop
5 anchor C:\

移動和刪除文件

當然 pathlib 還可以支持文件其他操作,像移動,更新,甚至刪除文件,但是使用這些方法的時候要小心因為,使用過程不用有任何的錯誤提示即使文件不存在也不會出現等待的情況。

使用 replace 方法可以移動文件,如果文件存在則會覆蓋。為避免文件可能被覆蓋,最簡單的方法是在替換之前測試目標是否存在。

1 import pathlib
2 
3 destination = pathlib.Path.cwd() / "123.txt"
4 source = pathlib.Path.cwd() / "123.txt"
5 if not destination.exists():
6     source.replace(destination)

但是上面的方法存在問題就是,在多個進程多 destination 進行的操作的時候就會現問題,可以使用下面的方法避免這個問題。也就是說上面的方法適合單個文件的操作。

1 import pathlib
2 
3 destination = pathlib.Path.cwd() / "123.txt"
4 source = pathlib.Path.cwd() / "123.txt"
5 with destination.open(mode='xb') as fid:
6     #xb表示文件不存在才操作
7     fid.write(source.read_bytes())

當 destination文件存在的時候上面的代碼就會出現 FileExistsError 異常。
從技術上講,這會復制一個文件。 要執行移動,只需在復制完成后刪除源即可。
使用 with_name with.shuffix 可以修改文件名字或者后綴。

1 import pathlib
2 source = pathlib.Path.cwd() / "demo.py"
3 source.replace(source.with_suffix(".txt")) #修改后綴並移動文件,即重命名

可以使用 .rmdir().unlink() 來刪除文件。

1 import pathlib
2  
3 destination = pathlib.Path.cwd() / "target" 
4 source = pathlib.Path.cwd() / "demo.txt"
5 source.unlink()

幾個 pathlib 的使用例子

統計文件個數

我們可以使用.iterdir方法獲取當前文件下的所以文件.

1 import pathlib
2 from collections import Counter
3 now_path = pathlib.Path.cwd()
4 gen = (i.suffix for i in now_path.iterdir())
5 print(now_path)
6 print(Counter(gen))

pathlib 也有 glob 方法和 rglob 方法,不同的是 glob 模塊里的 glob 方法結果是列表形式的,iglob 是生成器類型,在這里 pathlib 的 glob 模塊返回的是生成器類型,然后 pathlib 還有一個支持遞歸操作的 rglob 方法。

下面的這個操作我通過使用 glob 方法,設定規則進行文件的匹配。

1 import pathlib
2 
3 from collections import Counter
4 gen = (p.suffix for p in pathlib.Path.cwd().glob('*.py'))
5 print(gen)
6 print(Counter(gen))

輸出:

1 <generator object <genexpr> at 0x000001B3D528F8B8>
2 Counter({'.py': 6})

展示目錄樹

下一個示例定義了一個函數 tree(),該函數的作用是打印一個表示文件層次結構的可視樹,該樹以一個給定目錄為根。因為想列出其子目錄,所以我們要使用 .rglob() 方法:

 1 import pathlib
 2 
 3 
 4 from collections import Counter
 5 def tree(directory):
 6     print(f'+ {directory}')
 7     for path in sorted(directory.rglob('*')):
 8         # print(path.relative_to(directory))
 9         # print(path.relative_to(directory).parts)
10         depth = len(path.relative_to(directory).parts)
11         spacer = '    ' * depth
12         print(f'{spacer}+{path.name}')
13 
14 tree(pathlib.Path.cwd())

其中 relative_to 的方法的作用是返回 path 相對於 directory 的路徑。
parts 方法可以返回路徑的各部分。例如

1 import pathlib
2 now_path = pathlib.Path.cwd()
3 if __name__ == '__main__':
4     print(now_path.parts)

輸出:

1 ('C:\\', 'Users', 'huangm', 'Desktop')

獲取文件最后一次修改時間

iterdir(),.glob()和.rglob()方法非常適合於生成器表達式和列表理解。
使用stat()方法可以獲取文件的一些基本信息,使用.stat().st_mtime可以獲取文件最后一次修改的信息

1 import pathlib
2 now_path = pathlib.Path.cwd()
3 from datetime import datetime
4 time, file_path = max((f.stat().st_mtime, f) for f in now_path.iterdir())
5 print(datetime.fromtimestamp(time), file_path)

甚至可以使用類似的表達式獲取上次修改的文件內容

1 import pathlib
2 from datetime import datetime
3 now_path =pathlib.Path.cwd()
4 result = max((f.stat().st_mtime, f) for f in now_path.iterdir())[1]
5 print(result.read_text())

其他內容

關於 pathlib.Path 格式路徑轉換為字符串類型

因為通過 pathlib 模塊操作生成的路徑,不能直接應用字符串的一些操作,所以需要轉換成字符串,雖然可以使用 str() 函數進行轉換,但是安全性不高,建議使用 os.fspath() 方法,因為如果路徑格式非法的,可以拋出一個異常。str()就不能做到這一點。

拼接符號”/”背后的秘密

/ 運算符由 __truediv__ 方法定義。 實際上,如果你看一下 pathlib 的源代碼,你會看到類似的東西。

1 class PurePath(object):
2  
3     def __truediv__(self, key):
4         return self._make_child((key,))

參考文章:

https://realpython.com/python-pathlib/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM