简介

官方文档将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)  
os.rename("./src/stuff", "./src/config")  

pathlib

from pathlib import Path

Path("./src/stuff").mkdir(parents=True, exist_ok=True)  
Path("./src/stuff").rename("./src/config")  
参数 含义
parents 找不到父目录会根据此路径创建
exist_ok 允许存在不抛出异常FileExistsError

递归列出某类型文件

假设目录:

    .
      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)

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))

打开多个文件并读取内容

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)

属性和方法

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)

父目录 Path.parents & Path.parent

from pathlib import Path

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

for parent in file_path.parents:
    print(parent)




print(file_path.parent)

文件名或目录名 Path.name

os.path

import os

print(os.path.basename("src/config/__init__.py"))
print(os.path.basename("src/config"))

pathlib

from pathlib import Path

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

文件名后缀 Path.suffixes & Path.suffix

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

os.path

import os

print(os.path.splitext("src/config/somefile.tar.gz"))

pathlib

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.suffixes)
print(file_path.suffix)

不带后缀文件名 Path.stem

os.path(只有一个的情况下有坑)

import os


def stem(path):
    path = os.path.basename(path)
    i = path.rfind('.')
    if 0 < i < len(path) - 1:
        return path[:i]
    else:
        return path


print(stem("/Library/Python.framework/Versions/3.6/bin/python3"))
print(stem("src/config/__init__.py"))
print(stem("src/config/somefile.tar.gz"))
print('.'.join(os.path.basename("src/config/__init__.py").split('.')[:-1]))
print('.'.join(os.path.basename("src/config/somefile.tar.gz").split('.')[:-1]))

pathlib

from pathlib import Path

print(Path("/Library/Python.framework/Versions/3.6/bin/python3").stem)
print(Path("src/config/__init__.py").stem)
print(Path("src/config/somefile.tar.gz").stem)

修改文件名

from pathlib import Path

filename = Path('/data/pic/图片.jpg')
targetname = filename.parent / (filename.stem + f'_1{filename.suffix}')
print(targetname)

从右往左替换字符串

def right_replace(s, old, new, count=None):
    """从右到左替换字符串"""
    if count:
        return s[::-1].replace(old[::-1], new[::-1], count)[::-1]
    else:
        return s[::-1].replace(old[::-1], new[::-1])[::-1]


print(right_replace('1.docx', '.docx', '.pdf'))

是否为绝对路径 Path.is_absolute()

from pathlib import Path

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

组合路径 Path.joinpath(*other)

from pathlib import Path

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

当前工作目录 Path.cwd()

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.cwd())

根目录 Path.home()

from pathlib import Path

file_path = Path("src/config/somefile.tar.gz")
print(file_path.home())

是否存在路径 Path.exists()

os.path

import os.path

print(os.path.exists("src/config/aaaa.py"))

pathlib

from pathlib import Path

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

返回带~和~user的路径 Path.expanduser()

from pathlib import Path

file_path = Path("~/code/test/src/config/somefile.tar.gz")
print(file_path.expanduser())

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

from pathlib import Path

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

print(list(file_paths))

递归列出匹配的文件或目录 Path.rglob()

from pathlib import Path

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

print(list(file_paths))

是否为目录或文件 Path.is_dir() & Path.is_file()

from pathlib import Path

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

列出路径下的文件和目录 Path.iterdir()

from pathlib import Path

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

print(contents)

新建目录 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())

strict设为True,如果路径不存在,则抛出FileNotFoundError

删除目录 Path.rmdir()

os.path

import os

os.rmdir("src/other/side")

如果目录下不为空,抛出OSError

pathlib

from pathlib import Path

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

如果目录下不为空,抛出OSError

删除文件 os.remove()

删除文件还是要用os模块

os

import os

os.remove("src/other/side/a.txt")

移动文件 shutil.move()

shutil

import shutil

shutil.move('a/test.txt', '.')

pathlib

from pathlib import Path

path = Path('a/test.txt')
folder = Path('.')
path.rename(folder / path.name)

转Unix风格

as_posix():返回使用正斜杠(/)的路径字符串

from pathlib import Path

path = Path('/host/share')
print(str(path))  
print(path.as_posix())  

对应关系

功能 os 和 os.path pathlib
绝对路径 os.path.abspath() Path.resolve()
改变文件的模式和权限 os.chmod() Path.chmod()
新建目录 os.mkdir() Path.mkdir()
新建目录 os.makedirs() Path.mkdir()
重命名 os.rename() Path.rename()
覆盖 os.replace() Path.replace()
删除目录 os.rmdir() Path.rmdir()
移除此文件或符号链接 os.remove(), os.unlink() Path.unlink()
当前工作目录 os.getcwd() Path.cwd()
是否存在路径 os.path.exists() Path.exists()
根目录 os.path.expanduser() Path.expanduser() 和 Path.home()
列出路径下的文件和目录 os.listdir() Path.iterdir()
是否为目录 os.path.isdir() Path.is_dir()
是否为文件 os.path.isfile() Path.is_file()
是否指向符号链接 os.path.islink() Path.is_symlink()
创建硬链接 os.link() Path.link_to()
将此路径创建为符号链接 os.symlink() Path.symlink_to()
返回符号链接所指向的路径 os.readlink() Path.readlink()
返回 os.stat_result 对象包含此路径信息 os.stat() Path.stat(), Path.owner(), Path.group()
是否为绝对路径 os.path.isabs() PurePath.is_absolute()
连接路径 os.path.join() PurePath.joinpath()
文件名或目录名 os.path.basename() PurePath.name
父目录 os.path.dirname() PurePath.parent
是否相同文件 os.path.samefile() Path.samefile()
文件名后缀 os.path.splitext() PurePath.suffix
移动文件 shutil.move() Path.rename()

常用脚本

1. 移动子文件夹下的所有文件到本文件夹

import shutil
from pathlib import Path

paths = Path('.').rglob('*')
for path in paths:
    if str(path.absolute()) == __file__:  
        continue
    if str(path.parent) == '.':  
        continue
    if path.is_file():
        try:
            shutil.move(str(path), '.')
        except Exception as e:
            print(e)

2. 批量重命名

import os
from pathlib import Path

path = 'E:\迅雷下载\Shaman King'  
os.chdir(path)  

p = Path('.').glob('*')
for i in p:
    newname = i.name.split(' RAW')  
    print(newname[0] + '.mp4')
    i.rename(newname[0] + '.mp4')

3. 获取文件大小

import os
from pathlib import Path

print(os.path.getsize('a.txt'))
print(Path('a.txt').stat().st_size)



from pathlib import Path


def human_size(size, decimal_places=2):
    """字节大小转人类可读大小"""
    units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']
    for unit in units:
        if size < 1024.0 or unit == units[-1]:
            break
        size /= 1024.0
    if isinstance(size, int):
        decimal_places = 0
    return f'{size:.{decimal_places}f}{unit}'


for file in Path('.').glob('*'):
    if file.is_file():
        bytes = file.stat().st_size
        print(file, human_size(bytes))

4. 去除文件名后缀

from pathlib import Path

name = Path('a.jpg').stem
print(name, type(name))

5. 修改文件名后缀

from pathlib import Path

for filename in ['a.py', 'src/config/a.py']:
    filename = Path(filename)
    new_filename = f'{filename.parent / filename.stem}.jpg'
    print(new_filename)

参考文献

  1. pathlib — 面向对象的文件系统路径
  2. No Really, Python’s Pathlib is Great
  3. os.path — 常用路径操作
  4. os — 多种操作系统接口
  5. shutil — 高阶文件操作
  6. Python改变当前工作目录
  7. 利用replace方法实现从右到左替换字符串
  8. How do I check file size in Python

文章转自:https://blog.csdn.net/lly1122334/article/details/106328494