python的文件操作
什么是pathlib?
pathlib是Python 3.4引入的一个内置模块,提供了一种面向对象的方式来处理文件系统路径。
核心思想:把路径当作对象,而不是字符串
from pathlib import Path
# 创建Path对象
path = Path('folder/subfolder/file.txt')
# 现在path是一个对象,有各种方法
print(f"路径:{path}")
print(f"类型:{type(path)}") # <class 'pathlib.PosixPath'> 或 WindowsPath
创建Path对象
基本创建
from pathlib import Path
# 从字符串创建
p1 = Path('folder/file.txt')
p2 = Path('/home/user/documents') # 绝对路径
p3 = Path('.') # 当前目录
p4 = Path('..') # 上级目录
# 创建空路径
p5 = Path() # 当前目录
特殊路径
from pathlib import Path
# 当前工作目录
current = Path.cwd()
print(f"当前目录:{current}")
# 用户家目录
home = Path.home()
print(f"家目录:{home}")
# 在Windows上:
# Path('C:/Users/Username/Documents')
# 在Linux/Mac上:
# Path('/home/username/Documents')
跨平台路径(最重要的优势!)
from pathlib import Path
# 写法1:用正斜杠(推荐)
path1 = Path('folder/subfolder/file.txt')
# 写法2:用Path对象拼接
path2 = Path('folder') / 'subfolder' / 'file.txt'
# 在Windows上会自动转换为反斜杠
# 在Linux/Mac上保持不变
print(path1) # Windows: folder\subfolder\file.txt
# Linux: folder/subfolder/file.txt
路径拼接和分解
使用 /运算符拼接
from pathlib import Path
# 创建基础路径
base = Path('/home/user')
# 使用 / 运算符拼接(最方便!)
documents = base / 'Documents'
file_path = documents / 'report.docx'
print(f"文档路径:{documents}")
print(f"文件路径:{file_path}")
# 可以连续拼接
path = Path('/') / 'usr' / 'local' / 'bin' / 'python'
print(f"Python路径:{path}")
使用 joinpath() 方法
from pathlib import Path
# joinpath() 方法
path = Path('/home/user').joinpath('Documents', 'file.txt')
print(path)
分解路径的各部分
from pathlib import Path
path = Path('/home/user/Documents/report.docx')
# 获取路径的各个部分
print(f"完整路径:{path}")
print(f"父目录:{path.parent}")
print(f"父目录的父目录:{path.parent.parent}")
print(f"文件名(带扩展名):{path.name}")
print(f"文件名(不带扩展名):{path.stem}")
print(f"扩展名:{path.suffix}")
print(f"所有父目录:{list(path.parents)}")
print(f"锚点(根目录):{path.anchor}")
输出示例:
完整路径:/home/user/Documents/report.docx
父目录:/home/user/Documents
父目录的父目录:/home/user
文件名(带扩展名):report.docx
文件名(不带扩展名):report
扩展名:.docx
所有父目录:[PosixPath('/home/user/Documents'), PosixPath('/home/user'), PosixPath('/home'), PosixPath('/')]
锚点(根目录):/
路径检查和判断
检查路径是否存在
from pathlib import Path
path = Path('some_file.txt')
# 检查是否存在
if path.exists():
print(f"{path} 存在")
else:
print(f"{path} 不存在")
# 检查是否是文件
if path.is_file():
print(f"{path} 是文件")
# 检查是否是目录
if path.is_dir():
print(f"{path} 是目录")
# 检查是否是符号链接
if path.is_symlink():
print(f"{path} 是符号链接")
# 检查是否是绝对路径
if path.is_absolute():
print(f"{path} 是绝对路径")
else:
print(f"{path} 是相对路径")
获取绝对路径
from pathlib import Path
# 相对路径转绝对路径
relative = Path('folder/file.txt')
absolute = relative.resolve() # 解析为绝对路径
print(f"相对路径:{relative}")
print(f"绝对路径:{absolute}")
# 注意:resolve() 会解析符号链接
# 如果不解析符号链接,用absolute()
abs_path = relative.absolute()
文件和目录操作
创建目录
from pathlib import Path
# 创建单个目录
new_dir = Path('new_folder')
new_dir.mkdir() # 如果目录已存在会报错
# 解决方法:
new_dir.mkdir(exist_ok=True) # 存在时不报错
# 创建多级目录
deep_dir = Path('a/b/c/d/e')
deep_dir.mkdir(parents=True, exist_ok=True) # 自动创建父目录
删除文件和目录
from pathlib import Path
# 删除文件
file_path = Path('temp.txt')
if file_path.exists():
file_path.unlink() # 删除文件
print(f"已删除文件:{file_path}")
# 删除空目录
empty_dir = Path('empty_folder')
if empty_dir.exists() and empty_dir.is_dir():
empty_dir.rmdir() # 只能删除空目录
print(f"已删除目录:{empty_dir}")
# 删除非空目录(需要shutil)
import shutil
non_empty_dir = Path('non_empty_folder')
if non_empty_dir.exists():
shutil.rmtree(non_empty_dir) # 递归删除
print(f"已删除非空目录:{non_empty_dir}")
重命名和移动
from pathlib import Path
# 重命名文件
old_file = Path('old_name.txt')
new_file = Path('new_name.txt')
if old_file.exists():
old_file.rename(new_file)
print(f"重命名:{old_file} -> {new_file}")
# 移动文件(实际是重命名到不同路径)
source = Path('source_folder/file.txt')
target = Path('target_folder/file.txt')
# 确保目标目录存在
target.parent.mkdir(parents=True, exist_ok=True)
if source.exists():
source.rename(target)
print(f"移动文件:{source} -> {target}")
文件内容读写
读写文本文件
from pathlib import Path
# 写入文本文件
file_path = Path('example.txt')
# 写入内容(覆盖)
file_path.write_text("Hello, World!\n你好,世界!", encoding='utf-8')
# 追加内容
with file_path.open('a', encoding='utf-8') as f:
f.write("\n这是追加的内容")
# 读取内容
content = file_path.read_text(encoding='utf-8')
print("文件内容:")
print(content)
# 按行读取
lines = file_path.read_text(encoding='utf-8').splitlines()
for i, line in enumerate(lines, 1):
print(f"第{i}行:{line}")
读写二进制文件
from pathlib import Path
# 写入二进制文件
data = b'Binary data: \x00\x01\x02\x03'
file_path = Path('data.bin')
file_path.write_bytes(data)
# 读取二进制文件
read_data = file_path.read_bytes()
print(f"读取的数据:{read_data}")
使用open()方法
from pathlib import Path
file_path = Path('data.txt')
# 像内置open一样使用
with file_path.open('w', encoding='utf-8') as f:
f.write("使用open方法写入\n")
f.write("第二行内容\n")
# 读取
with file_path.open('r', encoding='utf-8') as f:
for line in f:
print(f"读取:{line.strip()}")
遍历目录和文件搜索
遍历目录内容
from pathlib import Path
# 遍历当前目录
current = Path('.')
print("当前目录内容:")
for item in current.iterdir():
if item.is_file():
print(f"文件:{item.name}")
elif item.is_dir():
print(f"目录:{item.name}")
使用glob模式匹配
from pathlib import Path
# 创建一些测试文件
for i in range(5):
Path(f'test_{i}.txt').touch()
Path(f'data_{i}.csv').touch()
Path('image.jpg').touch()
Path('document.pdf').touch()
# 使用glob查找
print("所有.txt文件:")
for txt_file in Path('.').glob('*.txt'):
print(f" {txt_file.name}")
print("\n所有.csv文件:")
for csv_file in Path('.').glob('*.csv'):
print(f" {csv_file.name}")
# 使用rglob递归查找
print("\n递归查找所有.txt文件:")
for txt_file in Path('.').rglob('*.txt'):
print(f" {txt_file}")
更复杂的模式匹配
from pathlib import Path
# 匹配多个模式
for file in Path('.').glob('*.{txt,csv,json}'):
print(f"文本/数据文件:{file}")
# 匹配特定模式
for file in Path('.').glob('test_?.txt'): # test_1.txt, test_2.txt等
print(f"测试文件:{file}")
# 匹配目录
for dir in Path('.').glob('*/'): # 注意斜杠表示目录
print(f"子目录:{dir}")
获取文件信息
文件属性
from pathlib import Path
import datetime
file_path = Path('example.txt')
# 如果文件存在,获取属性
if file_path.exists():
stat_info = file_path.stat()
print("=== 文件属性 ===")
print(f"文件大小:{stat_info.st_size} 字节")
print(f"最后访问时间:{datetime.datetime.fromtimestamp(stat_info.st_atime)}")
print(f"最后修改时间:{datetime.datetime.fromtimestamp(stat_info.st_mtime)}")
print(f"创建时间:{datetime.datetime.fromtimestamp(stat_info.st_ctime)}")
# 权限信息
import stat
print(f"权限:{oct(stat_info.st_mode)[-3:]}")
print(f"是否可读:{stat_info.st_mode & stat.S_IRUSR != 0}")
print(f"是否可写:{stat_info.st_mode & stat.S_IWUSR != 0}")
print(f"是否可执行:{stat_info.st_mode & stat.S_IXUSR != 0}")
文件所有者
from pathlib import Path
import pwd # Unix系统
import grp # Unix系统
file_path = Path('example.txt')
if file_path.exists():
stat_info = file_path.stat()
# 获取所有者信息(Unix系统)
try:
owner = pwd.getpwuid(stat_info.st_uid).pw_name
group = grp.getgrgid(stat_info.st_gid).gr_name
print(f"所有者:{owner}:{group}")
except (ImportError, KeyError):
# Windows系统或无法获取
print(f"用户ID:{stat_info.st_uid}")
print(f"组ID:{stat_info.st_gid}")
实际应用示例
示例1:整理下载文件夹
from pathlib import Path
import shutil
def organize_downloads():
"""整理下载文件夹,按类型分类"""
download_folder = Path.home() / 'Downloads'
categories = {
'图片': ['.jpg', '.jpeg', '.png', '.gif', '.bmp'],
'文档': ['.pdf', '.docx', '.doc', '.txt', '.md'],
'压缩包': ['.zip', '.rar', '.7z', '.tar', '.gz'],
'程序': ['.exe', '.msi', '.dmg', '.pkg'],
'视频': ['.mp4', '.avi', '.mov', '.mkv'],
}
# 创建分类文件夹
for category in categories:
(download_folder / category).mkdir(exist_ok=True)
# 整理文件
moved_count = 0
for file_path in download_folder.iterdir():
if file_path.is_file():
# 根据扩展名分类
for category, extensions in categories.items():
if file_path.suffix.lower() in extensions:
target = download_folder / category / file_path.name
try:
file_path.rename(target)
moved_count += 1
print(f"移动:{file_path.name} -> {category}/")
break
except Exception as e:
print(f"移动失败 {file_path}: {e}")
print(f"\n整理完成!移动了 {moved_count} 个文件")
# 运行整理
organize_downloads()
示例2:批量重命名文件
from pathlib import Path
def batch_rename(folder, pattern, new_name):
"""
批量重命名文件
Args:
folder: 文件夹路径
pattern: 文件匹配模式,如 '*.jpg'
new_name: 新文件名模板,如 'image_{index:03d}.jpg'
"""
folder_path = Path(folder)
if not folder_path.exists():
print(f"错误:文件夹不存在 {folder}")
return
# 获取匹配的文件列表
files = list(folder_path.glob(pattern))
files.sort() # 按文件名排序
if not files:
print(f"没有找到匹配 {pattern} 的文件")
return
# 批量重命名
for index, old_path in enumerate(files, 1):
# 生成新文件名
new_filename = new_name.format(index=index)
new_path = folder_path / new_filename
# 重命名
try:
old_path.rename(new_path)
print(f"重命名:{old_path.name} -> {new_filename}")
except Exception as e:
print(f"重命名失败 {old_path}: {e}")
print(f"完成!重命名了 {len(files)} 个文件")
# 使用示例:重命名所有jpg图片
batch_rename('/path/to/photos', '*.jpg', 'vacation_{index:03d}.jpg')
示例3:备份重要文件
from pathlib import Path
import shutil
import datetime
def backup_files(source_dir, backup_dir, patterns):
"""
备份指定类型的文件
Args:
source_dir: 源目录
backup_dir: 备份目录
patterns: 文件匹配模式列表,如 ['*.py', '*.txt']
"""
source_path = Path(source_dir)
backup_path = Path(backup_dir)
# 创建带时间戳的备份文件夹
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
backup_folder = backup_path / f'backup_{timestamp}'
backup_folder.mkdir(parents=True, exist_ok=True)
print(f"开始备份到:{backup_folder}")
copied_count = 0
# 遍历所有匹配模式
for pattern in patterns:
for file_path in source_path.rglob(pattern):
if file_path.is_file():
# 保持目录结构
relative_path = file_path.relative_to(source_path)
target_path = backup_folder / relative_path
# 创建目标目录
target_path.parent.mkdir(parents=True, exist_ok=True)
# 复制文件
try:
shutil.copy2(file_path, target_path) # copy2保留元数据
copied_count += 1
print(f"备份:{relative_path}")
except Exception as e:
print(f"备份失败 {file_path}: {e}")
print(f"备份完成!共备份 {copied_count} 个文件")
# 使用示例
backup_files(
source_dir='/path/to/project',
backup_dir='/path/to/backups',
patterns=['*.py', '*.txt', '*.md', '*.json']
)
常见问题解答
Q1:什么时候用pathlib,什么时候用os.path?
A:总是用pathlib!除非你维护的是Python 3.4之前的旧代码。
pathlib更现代、更直观
统一了文件系统操作的接口
更好的跨平台支持
Q2:如何判断路径是文件还是目录?
from pathlib import Path
path = Path('some/path')
if path.exists():
if path.is_file():
print("是文件")
elif path.is_dir():
print("是目录")
else:
print("路径不存在")
Q3:如何处理路径中的特殊字符?
from pathlib import Path
# pathlib会自动处理特殊字符
path = Path('folder with spaces/file (1).txt')
print(path) # folder with spaces/file (1).txt
# 但要注意:有些字符是系统保留的
# Windows: < > : " | ? *
# Linux/Mac: / (路径分隔符)
Q4:如何获取文件大小?
from pathlib import Path
path = Path('large_file.zip')
if path.exists():
size_bytes = path.stat().st_size
size_mb = size_bytes / (1024 * 1024)
print(f"文件大小:{size_mb:.2f} MB")
Q5:如何清空目录但不删除目录本身?
from pathlib import Path
import shutil
def clear_directory(dir_path):
"""清空目录内容"""
dir_path = Path(dir_path)
if dir_path.exists() and dir_path.is_dir():
# 删除目录内所有内容
for item in dir_path.iterdir():
if item.is_file():
item.unlink()
elif item.is_dir():
shutil.rmtree(item)
print(f"已清空目录:{dir_path}")
else:
print(f"目录不存在:{dir_path}")
# 使用
clear_directory('temp_folder')

浙公网安备 33010602011771号