Python路徑操作庫pathlib,比os+glob+shutil更好用




簡介

官方文檔將pathlib稱爲面向對象的文件系統路徑,2019年Django將os.path替換成了pathlib

os.path一直是Python中處理路徑事實上的標準,但容易給人過於龐雜的感覺,而pathlib可以完成其絕大多數的任務。

pathlib在Python 3.4中引進,在Python 3.6中穩定。




現有問題

傳統上,Python將文件路徑表示爲常規文本字符串。然而,路徑實際上並不是字符串,因此完成功能需要使用多個模塊,包括osglobshutil等庫。

將當前目錄所有.py文件複製到另一個目錄,需要使用多達三個模塊:

import os
import shutil
from glob import glob

for f in glob("*.py"):
    path = os.path.join("./src", f)  # 新路徑
    shutil.copy(f, path)




創建新路徑

有文件file.txt,爲同一目錄下的file_another.txt構建路徑

os.path

from os.path import abspath, dirname, join

file_path = abspath("./file.txt")  # 絕對路徑
base_dir = dirname(file_path)  # 父目錄
file_another_path = join(base_dir, "file_another.txt")  # 構成新路徑
print("file_path:", file_path)
print("base_dir:", base_dir)
print("file_another_path:", file_another_path)

pathlib

from pathlib import Path

file_path = Path("file.txt").resolve()  # 絕對路徑
base_dir = file_path.parent  # 父目錄
file_another_path = base_dir / "another_file.txt"  # 構成新路徑
print("file_path:", file_path)
print("base_dir:", base_dir)
print("file_another_path:", file_another_path)

顯然用pathlib更加便捷




創建目錄和重命名

os.path

import os
import os.path

os.makedirs(os.path.join("./src", "stuff"), exist_ok=True)  # 構建目錄./src/stuff
os.rename("./src/stuff", "./src/config")  # 將./src/stuff重命名爲./src/config

pathlib

from pathlib import Path

Path("./src/stuff").mkdir(parents=True, exist_ok=True)  # 構建目錄./src/stuff
Path("./src/stuff").rename("./src/config")  # 將./src/stuff重命名爲./src/config




遞歸列出某類型文件

假設目錄:

.
│  file.txt
│  test.py
│
└─src
    └─config
            submodule.py
            __init__.py

列出所有.py文件

glob

from glob import glob

top_level_py_files = glob("./*.py")
all_py_files = glob("./**/*.py", recursive=True)  # 遞歸

print(top_level_py_files)
print(all_py_files)
# ['.\\test.py']
# ['.\\test.py', '.\\src\\config\\submodule.py', '.\\src\\config\\__init__.py']

pathlib

from pathlib import Path

top_level_py_files = Path(".").glob("*.py")
all_py_files = Path(".").rglob("*.py")  # 遞歸

print(list(top_level_py_files))
print(list(all_py_files))
# [WindowsPath('test.py')]
# [WindowsPath('test.py'), WindowsPath('src/config/submodule.py'), WindowsPath('src/config/__init__.py')]




打開多個文件並讀取內容

glob

from glob import glob

contents = []
for fname in glob("./**/*.py", recursive=True):
    with open(fname, "r") as f:
        contents.append(f.read())

print(contents)

pathlib幾乎相同

from pathlib import Path

contents = []
for fname in Path(".").rglob("*.py"):
    with open(fname, "r") as f:
        contents.append(f.read())

print(contents)




操作符

使用/取代os.path.join創建子目錄

from pathlib import Path

base_dir = Path("src")
child_dir = base_dir / "config"
file_path = child_dir / "__init__.py"

print(file_path)
# src\config\__init__.py




屬性和方法

Path

descriptor:
    parts: 每一層路徑
    parent: 父目錄
    parents: 所有父目錄
    name: 文件名或目錄名
    suffix: 文件名後綴
    suffixes: 文件名後綴列表
    stem: 不帶後綴文件名
function:
    is_absolute: 是否爲絕對路徑
    joinpath: 組合路徑
    cwd: 當前工作目錄
    home: 根目錄
    exists: 是否存在路徑
    expanduser: 返回帶~~user的路徑
    glob: 列出匹配的文件或目錄
    rglob: 遞歸列出匹配的文件或目錄
    is_dir: 是否爲目錄
    is_file: 是否爲文件
    iterdir: 列出路徑下的文件和目錄
    mkdir: 新建目錄
    open: 打開文件
    rename: 重命名
    replace: 覆蓋
    resolve: 轉成絕對路徑
    rmdir: 刪除目錄




路徑的每個位置 Path.parts

from pathlib import Path

file_path = Path("src/config/__init__.py")
print(file_path.parts)
# ('src', 'config', '__init__.py')




父目錄 Path.parents & Path.parent

from pathlib import Path

file_path = Path("src/config/__init__.py")

for parent in file_path.parents:
    print(parent)
    # src\config
    # src
    # .

print(file_path.parent)
# src\config




文件名或目錄名 Path.name

from pathlib import Path

print(Path("src/config/__init__.py").name)
print(Path("src/config").name)
# __init__.py
# config




文件名後綴 Path.suffixes & Path.suffix

在src/config/創建文件somefile.tar.gz

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.suffixes)
print(file_path.suffix)
# ['.tar', '.gz']
# .gz




不帶後綴文件名 Path.stem

from pathlib import Path

print(Path("src/config/__init__.py").stem)
print(Path("src/config/somefile.tar.gz").stem)
# __init__
# somefile.tar




是否爲絕對路徑 Path.is_absolute()

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.is_absolute())
# False




組合路徑 Path.joinpath(*other)

from pathlib import Path

file_path = Path("src").joinpath("config", "__init__.py")
print(file_path)
# src\config\__init__.py




當前工作目錄 Path.cwd()

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.cwd())
# D:\code\test




根目錄 Path.home()

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.home())
# C:\Users\Administrators




是否存在路徑 Path.exists()

from pathlib import Path

file_path = Path("src/config/aaaa.py")
print(file_path.exists())
# False




返回帶~和~user的路徑 Path.expanduser()

from pathlib import Path

file_path = Path("~/code/test/src/config/somefile.tar.gz")
print(file_path.expanduser())
# C:\Users\Administrators\code\test\src\config\somefile.tar.gz




列出匹配的文件或目錄 Path.glob()

from pathlib import Path

dir_path = Path("src/config/")
file_paths = dir_path.glob("*.py")

print(list(file_paths))
# [WindowsPath('src/config/submodule.py'), WindowsPath('src/config/__init__.py')]




遞歸列出匹配的文件或目錄 Path.rglob()

from pathlib import Path

dir_path = Path(".")
file_paths = dir_path.rglob("*.py")

print(list(file_paths))
# [WindowsPath('test.py'), WindowsPath('src/config/submodule.py'), WindowsPath('src/config/__init__.py')]




是否爲目錄或文件 Path.is_dir() & Path.is_file()

from pathlib import Path

dir_path = Path("src/config")
print(dir_path.is_dir())  # True
print(dir_path.is_file())  # False
file_path = Path("src/config/__init__.py")
print(file_path.is_dir())  # False
print(file_path.is_file())  # True




列出路徑下的文件和目錄 Path.iterdir()

from pathlib import Path

base_path = Path(".")
contents = [content for content in base_path.iterdir()]

print(contents)
# [WindowsPath('.idea'), WindowsPath('file.txt'), WindowsPath('src'), WindowsPath('test.py')]




新建目錄 Path.mkdir()

from pathlib import Path

dir_path = Path("src/other/side")
dir_path.mkdir(parents=True, exist_ok=True)

parents爲False,父目錄不存在時拋出FileNotFoundError

exist_ok爲False,該目錄存在時拋出FileExistsError




打開文件 Path.open()

同內置函數open()

from pathlib import Path

with Path("src/config/submodule.py") as f:
    contents = open(f, "r")
    for line in contents:
        print(line)




重命名 Path.rename()

from pathlib import Path

file_path = Path("src/config/submodule.py")
file_path.rename(file_path.parent / "anothermodule.py")




覆蓋 Path.replace()

使用給定的目錄(文件)覆蓋原目錄(文件)

from pathlib import Path

file_path = Path("src/config/anothermodule.py")
file_path.replace(file_path.parent / "Dockerfile")




轉成絕對路徑 Path.resolve()

from pathlib import Path

file_path = Path("src/config/Dockerfile")
print(file_path.resolve())
# D:\code\test\src\config\Dockerfile

strict設爲True,如果路徑不存在,則拋出FileNotFoundError




刪除目錄 Path.rmdir()

from pathlib import Path

file_path = Path("src/other/side")
file_path.rmdir()

如果目錄下不爲空,拋出OSError




參考文獻

  1. pathlib — 面向對象的文件系統路徑
  2. No Really, Python’s Pathlib is Great
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章