简介
官方文档将pathlib称为面向对象的文件系统路径,2019年Django将os.path
替换成了pathlib
。
os.path
一直是Python中处理路径事实上的标准,但容易给人过于庞杂的感觉,而pathlib
可以完成其绝大多数的任务。
pathlib
在Python 3.4中引进,在Python 3.6中稳定。
现有问题
传统上,Python将文件路径表示为常规文本字符串。然而,路径实际上并不是字符串,因此完成功能需要使用多个模块,包括os
、glob
和shutil
等库。
将当前目录所有.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)
参考文献
- pathlib — 面向对象的文件系统路径
- No Really, Python’s Pathlib is Great
- os.path — 常用路径操作
- os — 多种操作系统接口
- shutil — 高阶文件操作
- Python改变当前工作目录
- 利用replace方法实现从右到左替换字符串
- How do I check file size in Python
文章转自:https://blog.csdn.net/lly1122334/article/details/106328494