摘要:import os# 路径拼接path = os.path.join('dir', 'subdir', 'File.txt')# 检查是否存在if os.path.exists(path):# 获取文件名filename = os.path.basename(
我们学习 Day 10:使用 pathlib 处理路径。这是 Python 3.4+ 中处理文件系统路径的现代、面向对象的方式。
传统方式(os.path)
import os# 路径拼接path = os.path.join('dir', 'subdir', 'File.txt')# 检查是否存在if os.path.exists(path):# 获取文件名filename = os.path.basename(path)# 获取目录名dirname = os.path.dirname(path)现代方式(pathlib):
from pathlib import Path# 路径对象path = Path('dir') / 'subdir' / 'file.txt'# 检查是否存在if path.exists:# 获取文件名filename = path.name# 获取目录名dirname = path.parentfrom pathlib import Path# 多种创建方式p1 = Path('file.txt') # 相对路径p2 = Path('/home/user/file.txt') # 绝对路径p3 = Path # 当前目录p4 = Path.home # 用户家目录p5 = Path.cwd # 当前工作目录print(f"家目录: {Path.home}")print(f"当前目录: {Path.cwd}")路径拼接:
# 使用 / 操作符(推荐)path = Path('home') / 'user' / 'documents' / 'file.txt'print(path) # 输出: home/user/documents/file.txt# 连接多个部分path = Path('base') / 'subdir' / Path('file.txt')路径解析:
path = Path('/home/user/document/file.txt')print(f"文件名: {path.name}") # file.txtprint(f"主干名: {path.stem}") # fileprint(f"后缀名: {path.suffix}") # .txtprint(f"多个后缀: {path.suffixes}") # ['.txt']print(f"父目录: {path.parent}") # /home/user/documentprint(f"所有父目录: {list(path.parents)}") # [PosixPath('...'), ...]检查路径属性:
path = Path('example.txt')print(f"是否存在: {path.exists}")print(f"是文件: {path.is_file}")print(f"是目录: {path.is_dir}")print(f"是绝对路径: {path.is_absolute}")print(f"是符号链接: {path.is_symlink}")文件操作:
# 读写文件path = Path('test.txt')# 写入文件path.write_text('Hello, World!', encoding='utf-8')# 读取文件content = path.read_text(encoding='utf-8')print(content) # Hello, World!# 二进制操作path.write_bytes(b'Binary data')data = path.read_bytes目录操作:
# 创建目录dir_path = Path('my_directory')dir_path.mkdir(exist_ok=True) # exist_ok=True 避免目录已存在时报错# 创建多级目录nested_dir = Path('level1/level2/level3')nested_dir.mkdir(parents=True, exist_ok=True)# 遍历目录for item in Path('.').iterdir:print(f"{item.name} - {'目录' if item.is_dir else '文件'}")# 递归遍历for file in Path('.').rglob('*.py'): # 递归查找所有.py文件print(file)通配符匹配:
# 查找当前目录的所有.py文件for py_file in Path('.').glob('*.py'):print(py_file)# 递归查找所有.py文件for py_file in Path('.').rglob('*.py'):print(py_file)# 多个模式匹配patterns = ['*.py', '*.txt', '*.md']for pattern in patterns:for file in Path('.').glob(pattern):print(file)路径统计:
path = Path('some_file.txt')if path.exists:print(f"文件大小: {path.stat.st_size} 字节")print(f"修改时间: {path.stat.st_mtime}")print(f"创建时间: {path.stat.st_ctime}")移动和重命名
source = Path('old_name.txt')destination = Path('new_name.txt')# 重命名/移动文件source.rename(destination)# 也可以使用 replace(如果目标存在会替换)source.replace(destination)删除操作:
# 删除文件file_path = Path('file_to_delete.txt')if file_path.exists:file_path.unlink # 删除文件# 删除空目录empty_dir = Path('empty_directory')if empty_dir.exists and empty_dir.is_dir:empty_dir.rmdir# 删除非空目录(需要小心使用!)import shutilnon_empty_dir = Path('non_empty_directory')if non_empty_dir.exists:shutil.rmtree(non_empty_dir)场景1:项目文件管理
def organize_project_files(project_dir):"""整理项目文件"""project_path = Path(project_dir)# 创建标准目录结构directories = ['src', 'tests', 'docs', 'data', 'logs']for dir_name in directories:(project_path / dir_name).mkdir(exist_ok=True)# 移动Python文件到src目录for py_file in project_path.glob('*.py'):if py_file.name != 'setup.py':dest = project_path / 'src' / py_file.namepy_file.rename(dest)# 创建README文件readme = project_path / 'README.md'if not readme.exists:readme.write_text('# Project Name\n\nDescription goes here.')场景2:日志文件清理
def cleanup_old_logs(log_dir, days_old=30):"""清理指定天数前的日志文件"""from datetime import datetime, timedeltaimport timelog_path = Path(log_dir)cutoff_time = time.time - days_old * 24 * 3600for log_file in log_path.glob('*.log'):if log_file.stat.st_mtime场景3:配置文件查找
def find_config_files(config_name):"""在多个位置查找配置文件"""search_paths = [Path.cwd,Path.home / '.config',Path('/etc'),Path(__file__).parent # 脚本所在目录]for base_path in search_paths:config_path = base_path / config_nameif config_path.exists:return config_pathreturn None# 使用config_file = find_config_files('myapp.conf')if config_file:print(f"找到配置文件: {config_file}")content = config_file.read_textelse:print("未找到配置文件")技巧1:路径验证和规范化
def safe_path(base_dir, user_input):"""安全地处理用户输入的路径"""base_path = Path(base_dir).resolve # 解析为绝对路径user_path = Path(user_input)# 防止路径遍历攻击try:full_path = (base_path / user_path).resolve# 确保路径仍在基目录内if base_path in full_path.parents:return full_pathexcept ValueError:passreturn None# 安全地访问文件safe_file = safe_path('/var/www', 'uploads/image.jpg')if safe_file and safe_file.exists:content = safe_file.read_bytes技巧2:临时文件处理
from pathlib import Pathimport tempfiledef process_with_temp_file(data):"""使用临时文件处理数据"""with tempfile.NamedTemporaryFile(delete=False, suffix='.tmp') as tmp:tmp_path = Path(tmp.name)tmp.write(data.encode('utf-8'))try:# 处理临时文件result = process_file(tmp_path)return resultfinally:# 确保清理临时文件if tmp_path.exists:tmp_path.unlink技巧3:批量文件操作
def batch_rename_files(directory, pattern, new_pattern):"""批量重命名文件"""dir_path = Path(directory)for old_file in dir_path.glob(pattern):# 生成新文件名new_name = new_pattern.format(stem=old_file.stem,suffix=old_file.suffix,index=len(list(dir_path.glob(pattern))))new_file = dir_path / new_name# 重命名old_file.rename(new_file)print(f"重命名: {old_file.name} -> {new_file.name}")# 使用示例batch_rename_files('.', '*.txt', 'document_{index}{suffix}') 今日练习练习1:文件统计工具
def file_statistics(directory):"""统计目录中的文件信息:- 文件总数- 按扩展名分类的数量- 总大小- 最大的文件"""# 你的代码 herepass# 测试print(file_statistics('.'))练习2:项目结构检查
def check_project_structure(project_dir):"""检查项目目录结构是否完整应包含: src/, tests/, README.md, requirements.txt返回缺失的文件/目录列表"""# 你的代码 herepass# 测试missing = check_project_structure('.')print(f"缺失的项目文件: {missing}")练习3:安全文件查找
def find_files_safely(base_dir, pattern, max_depth=3):"""安全地递归查找文件,限制搜索深度防止性能问题"""# 你的代码 herepass# 测试files = find_files_safely('.', '*.py', max_depth=2)for file in files:print(file)练习答案:
# 练习1答案:def file_statistics(directory):from collections import Counterdir_path = Path(directory)if not dir_path.is_dir:return Nonefiles = list(dir_path.rglob('*'))files = [f for f in files if f.is_file]ext_counter = Counter(f.suffix for f in files)total_size = sum(f.stat.st_size for f in files)largest_file = max(files, key=lambda f: f.stat.st_size, default=None)return {'total_files': len(files),'by_extension': dict(ext_counter),'total_size': total_size,'largest_file': largest_file.name if largest_file else None}# 练习2答案:def check_project_structure(project_dir):required = ['src','tests', 'README.md','requirements.txt']project_path = Path(project_dir)missing = for item in required:path = project_path / itemif not path.exists:missing.append(item)return missing# 练习3答案:def find_files_safely(base_dir, pattern, max_depth=3):base_path = Path(base_dir)results = def search_recursive(current_path, current_depth):if current_depth > max_depth:returntry:for item in current_path.iterdir:if item.is_file and item.match(pattern):results.append(item)elif item.is_dir:search_recursive(item, current_depth + 1)except PermissionError:pass # 跳过无权限的目录search_recursive(base_path, 0)return results新项目优先使用 pathlib 而不是 os.path使用 / 操作符进行路径拼接利用 exists, is_file, is_dir 等方法进行路径检查使用 glob 和 rglob 进行文件查找来源:有趣的科技君