Python 路径操作与文件系统
目录
学习目标
- 掌握
pathlib模块的使用 - 理解面向对象的路径操作
- 学会遍历目录和处理文件路径
- 掌握文件元数据获取和权限操作
1. pathlib 基础
pathlib 是 Python 3.4+ 推荐的路径处理方式,用面向对象的方式替代 os.path。
1.1 创建路径对象
from pathlib import Path
# 当前目录
p = Path('.')
print(p) # .
# 绝对路径
p = Path('/usr/bin/python')
print(p) # /usr/bin/python
# 相对路径
p = Path('data/file.txt')
print(p) # data/file.txt
# 用户主目录
home = Path.home()
print(home) # /Users/username
# 当前工作目录
cwd = Path.cwd()
print(cwd)1.2 路径拼接
from pathlib import Path
# 使用 / 拼接路径
base = Path('/home/user')
path = base / 'documents' / 'file.txt'
print(path) # /home/user/documents/file.txt
# 混合使用字符串
path = Path('/home') / 'user' / 'test.py'
print(path)2. 路径属性和方法
2.1 路径组成部分
from pathlib import Path
p = Path('/home/user/documents/file.txt')
print(p.name) # file.txt(文件名)
print(p.stem) # file(不含后缀)
print(p.suffix) # .txt(后缀)
print(p.suffixes) # ['.txt'](所有后缀)
print(p.parent) # /home/user/documents(父目录)
print(p.parents) # 所有上级路径的序列
print(p.parts) # ('/', 'home', 'user', 'documents', 'file.txt')
print(p.anchor) # /(盘符或根)
# 多级父目录
for parent in p.parents:
print(parent)2.2 路径查询
from pathlib import Path
p = Path('example.txt')
print(p.exists()) # 是否存在
print(p.is_file()) # 是否是文件
print(p.is_dir()) # 是否是目录
print(p.is_absolute()) # 是否是绝对路径
# 文件元数据
if p.exists():
print(p.stat()) # 完整状态信息
print(p.stat().st_size) # 文件大小(字节)
print(p.stat().st_mtime) # 最后修改时间
# 路径信息
print(p.resolve()) # 解析为绝对路径3. 文件和目录操作
3.1 创建和删除
from pathlib import Path
# 创建目录
Path('new_folder').mkdir() # 创建单级目录
Path('a/b/c').mkdir(parents=True) # 递归创建
Path('a/b/c').mkdir(parents=True, exist_ok=True) # 已存在不报错
# 创建文件
Path('new_file.txt').touch() # 创建空文件
Path('new_file.txt').touch(exist_ok=True) # 已存在更新修改时间
# 删除
Path('file.txt').unlink() # 删除文件
Path('file.txt').unlink(missing_ok=True) # 不存在不报错
Path('empty_folder').rmdir() # 删除空目录
# 重命名
Path('old.txt').rename('new.txt')
Path('file.txt').replace('dest/file.txt') # 移动并覆盖3.2 读写文件
from pathlib import Path
p = Path('data.txt')
# 写入
p.write_text('Hello, World!', encoding='utf-8')
p.write_bytes(b'Binary data')
# 读取
content = p.read_text(encoding='utf-8')
data = p.read_bytes()
# 追加
with p.open('a', encoding='utf-8') as f:
f.write('\nAppend line')4. 目录遍历
4.1 遍历目录内容
from pathlib import Path
p = Path('.')
# 列出目录内容
for item in p.iterdir():
print(item)
# 筛选文件
files = [f for f in p.iterdir() if f.is_file()]
print(f"文件: {files}")
# 筛选目录
dirs = [d for d in p.iterdir() if d.is_dir()]
print(f"目录: {dirs}")4.2 通配符匹配
from pathlib import Path
p = Path('.')
# glob - 当前目录
py_files = list(p.glob('*.py'))
print(f"Python 文件: {py_files}")
# rglob - 递归所有子目录
all_py = list(p.rglob('*.py'))
print(f"所有 Python 文件: {all_py}")
# 匹配模式
# * 匹配任意字符
# ? 匹配单个字符
# ** 匹配任意目录层级
# 递归查找所有 .txt
for txt in p.rglob('**/*.txt'):
print(txt)4.3 递归遍历
from pathlib import Path
def tree(directory, prefix=''):
"""打印目录树"""
path = Path(directory)
# 获取目录内容并排序(目录在前,文件在后)
entries = sorted(path.iterdir(), key=lambda e: (e.is_file(), e.name))
for i, entry in enumerate(entries):
is_last = i == len(entries) - 1
current = '└── ' if is_last else '├── '
print(prefix + current + entry.name)
if entry.is_dir():
extension = ' ' if is_last else '│ '
tree(entry, prefix + extension)
# 使用
tree('.')5. 文件元数据和权限
5.1 获取元数据
from pathlib import Path
import datetime
p = Path('example.txt')
if p.exists():
stat = p.stat()
print(f"大小: {stat.st_size} 字节")
print(f"创建时间: {datetime.datetime.fromtimestamp(stat.st_ctime)}")
print(f"修改时间: {datetime.datetime.fromtimestamp(stat.st_mtime)}")
print(f"访问时间: {datetime.datetime.fromtimestamp(stat.st_atime)}")5.2 修改权限
from pathlib import Path
import stat
p = Path('script.sh')
# 添加可执行权限(Unix)
p.chmod(p.stat().st_mode | stat.S_IEXEC)
# 设置指定权限
p.chmod(0o755) # rwxr-xr-x
# 获取权限
mode = p.stat().st_mode
print(oct(mode)[-3:]) # 权限数字表示6. 实用示例
6.1 查找大文件
from pathlib import Path
def find_large_files(directory, min_size_mb=100):
"""查找大文件"""
min_bytes = min_size_mb * 1024 * 1024
path = Path(directory)
large_files = []
for file_path in path.rglob('*'):
if file_path.is_file() and file_path.stat().st_size > min_bytes:
size_mb = file_path.stat().st_size / (1024 * 1024)
large_files.append((file_path, size_mb))
return sorted(large_files, key=lambda x: x[1], reverse=True)
# 使用
# for path, size in find_large_files('.', 1):
# print(f"{path}: {size:.2f} MB")6.2 批量重命名
from pathlib import Path
def batch_rename(directory, old_ext, new_ext):
"""批量修改文件后缀"""
path = Path(directory)
for file_path in path.glob(f'*.{old_ext}'):
new_name = file_path.with_suffix(f'.{new_ext}')
file_path.rename(new_name)
print(f"重命名: {file_path.name} -> {new_name.name}")
# 使用
# batch_rename('.', 'txt', 'md')6.3 清理空目录
from pathlib import Path
def remove_empty_dirs(directory):
"""递归删除空目录"""
path = Path(directory)
for dir_path in path.rglob('*'):
if dir_path.is_dir():
try:
dir_path.rmdir() # 只能删除空目录
print(f"删除空目录: {dir_path}")
except OSError:
pass # 目录不为空
# 使用
# remove_empty_dirs('.')6.4 文件备份
from pathlib import Path
import shutil
from datetime import datetime
def backup_file(filepath):
"""创建文件备份"""
path = Path(filepath)
if not path.exists():
raise FileNotFoundError(f"文件不存在: {filepath}")
# 生成备份文件名
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_name = f"{path.stem}_{timestamp}{path.suffix}"
backup_path = path.parent / 'backup' / backup_name
# 确保备份目录存在
backup_path.parent.mkdir(exist_ok=True)
# 复制文件
shutil.copy2(path, backup_path)
print(f"备份创建: {backup_path}")
return backup_path
# 使用
# backup_file('important.txt')7. pathlib vs os.path
| 操作 | os.path | pathlib |
|---|---|---|
| 拼接路径 | os.path.join(a, b) |
Path(a) / b |
| 文件名 | os.path.basename(p) |
Path(p).name |
| 父目录 | os.path.dirname(p) |
Path(p).parent |
| 后缀 | os.path.splitext(p)[1] |
Path(p).suffix |
| 绝对路径 | os.path.abspath(p) |
Path(p).resolve() |
| 是否存在 | os.path.exists(p) |
Path(p).exists() |
# os.path 方式
import os.path
filepath = os.path.join(os.path.expanduser('~'), 'documents', 'file.txt')
filename = os.path.basename(filepath)
directory = os.path.dirname(filepath)
# pathlib 方式
from pathlib import Path
filepath = Path.home() / 'documents' / 'file.txt'
filename = filepath.name
directory = filepath.parent本节小结
- pathlib:面向对象的路径处理,替代 os.path
- 路径拼接:使用
/运算符 - 路径属性:
name、stem、suffix、parent等 - 目录遍历:
iterdir()、glob()、rglob() - 文件操作:
touch()、mkdir()、read_text()、write_text() - 推荐:新项目优先使用 pathlib
练习
- 编写一个函数,统计目录中各类文件的数量和总大小
- 实现一个文件搜索工具,支持按名称、大小、修改时间筛选
- 创建一个目录同步工具,将源目录的文件同步到目标目录
- 编写脚本,自动清理超过 N 天的临时文件