路径是文件或文件夹在计算机中的"地址"。就像家庭地址一样,路径告诉计算机去哪里找某个文件。
类比举例:
生活中的地址:中国 → 北京市 → 海淀区 → 中关村大街 → 18号 → 3单元 → 502室计算机文件路径:C: → Users → john → Documents → report.pdf
路径的两种表示方式
绝对路径:从根目录开始的完整路径
- Windows:
C:\Users\john\Documents\report.pdf - Mac/Linux:
/Users/john/Documents/report.pdf
相对路径:从当前所在位置开始的路径
./report.pdf../docs/readme.txt(上级目录的docs文件夹里的readme.txt)data/images/photo.jpg(当前目录下data/images里的photo.jpg)
特殊符号含义
1. Python的两种路径处理方式
Python主要提供了两种处理路径的方式:
- 传统方式:
os.path模块(Python诞生就有了) - 现代方式:
pathlib模块(Python 3.4引入)
os.path方式的特点
pathlib方式的特点
os 与 pathlib 功能对照速查表
"""功能 os.path pathlib--------------------------------------------------------------------------获取当前目录 os.getcwd() Path.cwd()获取用户目录 os.path.expanduser('~') Path.home()路径拼接 os.path.join(a, b) 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.splitext(os.path.basename(p))[0] Path(p).stem判断是否存在 os.path.exists(p) Path(p).exists()判断是文件 os.path.isfile(p) Path(p).is_file()判断是目录 os.path.isdir(p) Path(p).is_dir()获取绝对路径 os.path.abspath(p) Path(p).resolve()获取文件大小 os.path.getsize(p) Path(p).stat().st_size创建目录 os.mkdir(p) Path(p).mkdir()创建多级目录 os.makedirs(p) Path(p).mkdir(parents=True)删除文件 os.remove(p) Path(p).unlink()删除空目录 os.rmdir(p) Path(p).rmdir()重命名/移动 os.rename(old, new) Path(old).rename(new)列出目录 os.listdir(d) Path(d).iterdir()环境变量 os.environ['HOME'] os.environ.get('HOME')分割路径 os.path.split(p) [Path(p).parent, Path(p).name]相对路径 os.path.relpath(p, start) Path(p).relative_to(start)修改时间 os.path.getmtime(p) Path(p).stat().st_mtime创建时间(Windows) os.path.getctime(p) Path(p).stat().st_ctime权限检查 os.access(p, os.R_OK) os.access(str(p), os.R_OK)--------------------------------------------------------------------------"""
2. 具体操作对比
2.1 基础路径操作
import osfrom pathlib import Pathprint("="*60)print("获取当前路径")print("="*60)# os 方式os_cwd = os.getcwd()print(f"[os] 当前目录: {os_cwd}")# pathlib 方式pl_cwd = Path.cwd()print(f"[pathlib] 当前目录: {pl_cwd}")# 特殊路径print(f"[os] 用户目录: {os.path.expanduser('~')}")print(f"[pathlib] 用户目录: {Path.home()}")print(f"[os] 绝对路径: {os.path.abspath('.')}")print(f"[pathlib] 绝对路径: {Path('.').resolve()}")
2.2 路径拼接与组合
print("\n" + "="*60)print("路径拼接(最常用功能)")print("="*60)base = "/home/user"filename = "test.txt"subdir = "docs"# os 方式 - 多种方法os_path1 = os.path.join(base, subdir, filename)os_path2 = base + os.sep + subdir + os.sep + filenameprint(f"[os] 拼接结果: {os_path1}")# pathlib 方式 - 更优雅pl_base = Path(base)pl_path1 = pl_base / subdir / filenamepl_path2 = Path(base) / subdir / filenameprint(f"[pathlib] 拼接结果: {pl_path1}")# 实战:构建项目路径project_root = Path.cwd()data_dir = project_root / "data" / "raw"config_file = project_root / "config" / "settings.json"print(f"\n项目结构:")print(f" 数据目录: {data_dir}")print(f" 配置文件: {config_file}")
2.3 路径分解与解析
print("\n" + "="*60)print("路径分解(获取各部分)")print("="*60)filepath = "/home/user/docs/report.txt"# os 方式print("[os] 分解结果:")print(f" 目录名: {os.path.dirname(filepath)}")print(f" 文件名: {os.path.basename(filepath)}")name, ext = os.path.splitext(os.path.basename(filepath))print(f" 文件名(无扩展): {name}")print(f" 扩展名: {ext}")# pathlib 方式p = Path(filepath)print("\n[pathlib] 分解结果:")print(f" 父目录: {p.parent}")print(f" 文件名: {p.name}")print(f" 文件名(无扩展): {p.stem}")print(f" 扩展名: {p.suffix}")print(f" 所有父目录: {list(p.parents)}")
2.4 路径信息查询
print("\n" + "="*60)print("路径信息查询")print("="*60)test_path = "test.txt"# 先创建测试文件Path(test_path).touch()# os 方式print("[os] 文件信息:")print(f" 是否存在: {os.path.exists(test_path)}")print(f" 是否是文件: {os.path.isfile(test_path)}")print(f" 是否是目录: {os.path.isdir(test_path)}")print(f" 文件大小: {os.path.getsize(test_path)} 字节")print(f" 最后修改: {os.path.getmtime(test_path)}")# pathlib 方式p = Path(test_path)print("\n[pathlib] 文件信息:")print(f" 是否存在: {p.exists()}")print(f" 是否是文件: {p.is_file()}")print(f" 是否是目录: {p.is_dir()}")print(f" 文件大小: {p.stat().st_size} 字节")print(f" 最后修改: {p.stat().st_mtime}")# 清理p.unlink()
2.5 目录操作
print("\n" + "="*60)print("目录操作")print("="*60)# 创建目录test_dir = "test_dir"# os 方式try: os.mkdir(test_dir) # 只能创建一级print(f"[os] 创建目录: {test_dir}")except FileExistsError:print("[os] 目录已存在")# pathlib 方式p = Path(test_dir)p.mkdir(exist_ok=True) # 存在也不报错print(f"[pathlib] 创建/确认目录: {p}")# 创建多级目录nested_dir = "a/b/c/d"# os 方式os.makedirs(nested_dir, exist_ok=True)print(f"[os] 创建多级目录: {nested_dir}")# pathlib 方式Path(nested_dir).mkdir(parents=True, exist_ok=True)print(f"[pathlib] 创建多级目录: {nested_dir}")# 列出目录内容print("\n目录内容:")# os 方式print("[os] 简单列表:")for item in os.listdir('.'):print(f" {item}")# pathlib 方式print("\n[pathlib] 丰富列表:")for item in Path('.').iterdir(): type_icon = "📄"if item.is_file() else"📁"print(f" {type_icon}{item.name}")
2.6 文件操作
print("\n" + "="*60)print("文件操作")print("="*60)# 创建测试文件test_file = Path("test.txt")test_file.write_text("Hello World", encoding='utf-8')# 重命名/移动# os 方式os.rename("test.txt", "renamed.txt")print(f"[os] 重命名: test.txt -> renamed.txt")# pathlib 方式Path("renamed.txt").rename("final.txt")print(f"[pathlib] 重命名: renamed.txt -> final.txt")# 删除文件# os 方式os.remove("final.txt")print(f"[os] 删除文件")# 重新创建用于演示Path("test.txt").write_text("test")# pathlib 方式Path("test.txt").unlink()print(f"[pathlib] 删除文件")# 复制文件(两个库都需要额外模块)import shutilPath("source.txt").write_text("source")shutil.copy2("source.txt", "dest.txt")print(f"文件复制: source.txt -> dest.txt")# 清理Path("source.txt").unlink()Path("dest.txt").unlink()
2.7 路径属性与权限
print("\n" + "="*60)print("路径属性与权限")print("="*60)import statimport timetest_file = Path("test_permissions.txt")test_file.touch()# os 方式st = os.stat(test_file)print("[os] 文件属性:")print(f" 权限: {oct(st.st_mode)[-3:]}")print(f" 用户ID: {st.st_uid}")print(f" 组ID: {st.st_gid}")print(f" 修改时间: {time.ctime(st.st_mtime)}")# 检查权限print(f" 可读: {os.access(test_file, os.R_OK)}")print(f" 可写: {os.access(test_file, os.W_OK)}")print(f" 可执行: {os.access(test_file, os.X_OK)}")# pathlib 方式print("\n[pathlib] 文件属性:")print(f" 权限: {oct(test_file.stat().st_mode)[-3:]}")print(f" 所有者: {test_file.owner()}")print(f" 所属组: {test_file.group()}")# 修改权限test_file.chmod(0o644)print(f" 修改后权限: {oct(test_file.stat().st_mode)[-3:]}")# 清理test_file.unlink()
3. 场景化应用对比
3.1 场景:批量重命名文件
defbatch_rename_os(directory, old_ext, new_ext):"""使用os模块批量重命名""" count = 0for filename in os.listdir(directory):if filename.endswith(old_ext): old_path = os.path.join(directory, filename) new_name = filename[:-len(old_ext)] + new_ext new_path = os.path.join(directory, new_name) os.rename(old_path, new_path) count += 1return countdefbatch_rename_pathlib(directory, old_ext, new_ext):"""使用pathlib批量重命名""" count = 0for file_path in Path(directory).glob(f"*{old_ext}"): new_path = file_path.with_suffix(new_ext) file_path.rename(new_path) count += 1return count# 测试# 创建测试文件test_dir = Path("test_batch")test_dir.mkdir(exist_ok=True)for i inrange(3): (test_dir / f"file{i}.txt").touch()print("批量重命名 .txt -> .md")print(f"[os] 重命名了 {batch_rename_os('test_batch', '.txt', '.md')} 个文件")print(f"[pathlib] 重命名了 {batch_rename_pathlib('test_batch', '.md', '.txt')} 个文件")# 清理import shutilshutil.rmtree(test_dir)
3.2 场景:遍历目录树
deftree_os(start_path, indent=""):"""使用os模块显示目录树""" items = os.listdir(start_path)for i, item inenumerate(items): path = os.path.join(start_path, item) is_last = i == len(items) - 1 prefix = "└── "if is_last else"├── "print(indent + prefix + item)if os.path.isdir(path): extension = " "if is_last else"│ " tree_os(path, indent + extension)deftree_pathlib(start_path, indent=""):"""使用pathlib显示目录树""" items = list(Path(start_path).iterdir())for i, item inenumerate(items): is_last = i == len(items) - 1 prefix = "└── "if is_last else"├── "print(indent + prefix + item.name)if item.is_dir(): extension = " "if is_last else"│ " tree_pathlib(item, indent + extension)# 创建测试目录结构test_root = Path("test_tree")test_root.mkdir(exist_ok=True)(test_root / "file1.txt").touch()(test_root / "dir1").mkdir()(test_root / "dir1" / "file2.txt").touch()(test_root / "dir1" / "subdir").mkdir()(test_root / "dir2").mkdir()(test_root / "dir2" / "file3.txt").touch()print("\n目录树 (os):")tree_os("test_tree")print("\n目录树 (pathlib):")tree_pathlib("test_tree")# 清理shutil.rmtree(test_root)
3.3 场景:配置文件管理
classConfigManager:"""配置文件管理器 - 展示两种方式的混合使用"""def__init__(self, app_name, use_pathlib=True):self.app_name = app_nameself.use_pathlib = use_pathlibdefget_config_dir(self):"""获取配置目录"""ifself.use_pathlib:# pathlib 方式 home = Path.home() config_dir = home / ".config" / self.app_nameelse:# os 方式 home = os.path.expanduser("~") config_dir = os.path.join(home, ".config", self.app_name)return config_dirdefensure_config_dir(self):"""确保配置目录存在""" config_dir = self.get_config_dir()ifself.use_pathlib: Path(config_dir).mkdir(parents=True, exist_ok=True)return config_direlse: os.makedirs(config_dir, exist_ok=True)return config_dirdefsave_config(self, data, filename="config.json"):"""保存配置""" config_dir = self.ensure_config_dir()ifself.use_pathlib: config_file = Path(config_dir) / filenameimport json config_file.write_text( json.dumps(data, indent=2, ensure_ascii=False), encoding='utf-8' )else: config_file = os.path.join(config_dir, filename)import jsonwithopen(config_file, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2, ensure_ascii=False)print(f"配置已保存: {config_file}")defload_config(self, filename="config.json"):"""加载配置""" config_dir = self.get_config_dir()ifself.use_pathlib: config_file = Path(config_dir) / filenameif config_file.exists():import jsonreturn json.loads(config_file.read_text(encoding='utf-8'))else: config_file = os.path.join(config_dir, filename)if os.path.exists(config_file):import jsonwithopen(config_file, 'r', encoding='utf-8') as f:return json.load(f)return {}# 测试print("\n配置文件管理演示:")config = ConfigManager("myapp", use_pathlib=True)config.save_config({"theme": "dark", "language": "zh-CN"})loaded = config.load_config()print(f"加载的配置: {loaded}")
4. 进阶技巧
4.1 pathlib 的链式操作
# pathlib 的优雅链式操作from pathlib import Path# 一行代码完成复杂操作backup_path = ( Path.cwd() .parent / "backups" / f"backup_{Path.cwd().name}")print(f"备份路径: {backup_path}")# 条件链式操作defget_log_file(ensure_exists=True): log_path = Path.home() / ".logs" / "app.log"if ensure_exists: log_path.parent.mkdir(parents=True, exist_ok=True) log_path.touch(exist_ok=True)return log_pathprint(f"日志文件: {get_log_file()}")
4.2 混合使用技巧
import osfrom pathlib import Pathdefbest_of_both_worlds():"""结合两种方式的优点"""# 用 pathlib 处理路径 data_dir = Path.home() / "data" data_dir.mkdir(exist_ok=True)# 但有时需要字符串路径(比如某些旧库) old_lib_path = str(data_dir / "file.txt")# 获取环境变量(只能用 os) db_url = os.environ.get('DATABASE_URL', 'sqlite:///default.db')# 检查权限(两者都可,但 os 更直接)if os.access(data_dir, os.W_OK):print(f"有写入权限: {data_dir}")return data_dir
4.3 性能对比
import timeitdefcompare_performance():"""对比两种方式的性能""" os_setup = """import os""" pathlib_setup = """from pathlib import Path"""# 测试路径拼接 os_join = """os.path.join('a', 'b', 'c', 'd', 'e')""" pathlib_join = """Path('a') / 'b' / 'c' / 'd' / 'e'""" os_time = timeit.timeit(os_join, setup=os_setup, number=100000) pl_time = timeit.timeit(pathlib_join, setup=pathlib_setup, number=100000)print(f"路径拼接性能对比 (10万次):")print(f" os.path: {os_time:.4f}秒")print(f" pathlib: {pl_time:.4f}秒")print(f" 用时差: {os_time - pl_time:.4f}秒,pathlib是os的 {pl_time/os_time:.2f}倍" )# 测试文件存在检查 os_exists = """os.path.exists('.')""" pathlib_exists = """Path('.').exists()""" os_time = timeit.timeit(os_exists, setup=os_setup, number=100000) pl_time = timeit.timeit(pathlib_exists, setup=pathlib_setup, number=100000)print(f"\n文件存在检查性能对比 (10万次):")print(f" os.path: {os_time:.4f}秒")print(f" pathlib: {pl_time:.4f}秒")print(f" 用时差: {os_time - pl_time:.4f}秒,pathlib是os的 {pl_time/os_time:.2f}倍" )# 运行性能测试compare_performance()
输出示例(Python:3.13.0,系统:Win10):
路径拼接性能对比 (10万次): os.path: 0.0881秒 pathlib: 0.3887秒 用时差: -0.3006秒,pathlib是os的 4.41倍文件存在检查性能对比 (10万次): os.path: 0.7271秒 pathlib: 1.7421秒 用时差: -1.0149秒,pathlib是os的 2.40倍
选择建议
"""1. 新手友好选择: 如果刚开始学习,用 pathlib,代码更易读 Python 3.6+ 项目2. 项目维护选择: 新项目用 pathlib,旧项目保持 os.path 风格一致 需要兼容 Python 2 使用大量遗留代码 简单的字符串操作3. 性能敏感选择: 大量路径操作(百万级)用 os.path 一般场景 pathlib 完全够用4. 需要面向对象特性:使用 pathlib - 链式操作 - 方法丰富 - 代码可读性好5. 混合使用原则: - 用 pathlib 处理路径逻辑 - 用 os 处理环境变量、权限等 - 需要字符串时用 str(Path对象)没有绝对的好坏,适合的就是最好的!"""
注意事项
"""1. 路径分隔符: - 永远不要手动拼接路径(不要用 + 或 f-string) - 使用 Path('/') 或 os.path.join()2. 相对路径陷阱: - 当前工作目录可能不是你想象的目录 - 使用 __file__ 获取脚本所在目录3. 权限问题: - 总是检查文件是否存在和可写 - 提供备用方案4. 编码问题: - 明确指定编码(尤其是中文) - 使用 pathlib 自动处理5. 异常处理: - FileNotFoundError - PermissionError - OSError"""
建议
"""对于大多数Python开发者,建议:1. 默认使用 pathlib - 代码更现代、更易读 - 面向对象风格更符合Python理念 - 自动处理跨平台问题2. 只在以下情况使用 os.path - 维护遗留代码 - 需要极致性能 - 与要求字符串路径的库交互3. 记住核心函数 - Path.cwd() # 当前目录 - Path.home() # 用户目录 - Path(__file__).parent # 脚本目录4. 养成好习惯 - 总是使用 Path 对象而不是字符串 - 总是指定文件编码 - 总是处理可能的异常"""
附录1:os.path详解
获取路径信息
import os# 获取当前工作目录(你当前在哪个文件夹)current_dir = os.getcwd()print(f"当前所在目录:{current_dir}")# 获取用户主目录home_dir = os.path.expanduser("~")print(f"用户主目录:{home_dir}")# 获取绝对路径abs_path = os.path.abspath("test.txt")print(f"test.txt的绝对路径:{abs_path}")
运行结果示例:
当前所在目录:D:\projects\python-tutorial用户主目录:C:\Users\你的用户名test.txt的绝对路径:D:\projects\python-tutorial\test.txt
路径拼接
import os# 基础拼接base_dir = "D:/projects"sub_dir = "data"filename = "config.json"# 方法1:使用os.path.join(推荐)file_path = os.path.join(base_dir, sub_dir, filename)print(f"拼接结果:{file_path}")# 方法2:手动拼接(容易出错)wrong_path = base_dir + "/" + sub_dir + "/" + filenameprint(f"手动拼接:{wrong_path}")# 方法3:使用字符串格式化another_path = f"{base_dir}/{sub_dir}/{filename}"print(f"格式化拼接:{another_path}")
为什么推荐os.path.join?
- 自动处理不同操作系统的分隔符(Windows用\,Mac/Linux用/)
路径分解
import osfilepath = "D:/projects/python-tutorial/data/config.json"# 获取目录部分directory = os.path.dirname(filepath)print(f"目录:{directory}")# 获取文件名部分filename = os.path.basename(filepath)print(f"文件名:{filename}")# 分离文件名和扩展名name_without_ext, extension = os.path.splitext(filename)print(f"文件名(无扩展):{name_without_ext}")print(f"扩展名:{extension}")# 分割路径(返回目录和文件名的元组)dir_part, file_part = os.path.split(filepath)print(f"分割结果:目录={dir_part}, 文件={file_part}")
路径判断
import os# 检查路径是否存在path = "test.txt"if os.path.exists(path):print(f"{path} 存在")else:print(f"{path} 不存在")# 判断是文件还是目录if os.path.isfile(path):print(f"{path} 是一个文件")elif os.path.isdir(path):print(f"{path} 是一个目录")else:print(f"{path} 既不是文件也不是目录")# 判断是否为绝对路径if os.path.isabs(path):print(f"{path} 是绝对路径")else:print(f"{path} 是相对路径")# 检查文件权限if os.access(path, os.R_OK):print(f"可以读取 {path}")if os.access(path, os.W_OK):print(f"可以写入 {path}")if os.access(path, os.X_OK):print(f"可以执行 {path}")
获取文件信息
import osimport timefilepath = "test.txt"# 确保文件存在withopen(filepath, "w") as f: f.write("测试内容")# 获取文件大小size = os.path.getsize(filepath)print(f"文件大小:{size} 字节")# 获取修改时间mtime = os.path.getmtime(filepath)print(f"最后修改时间:{time.ctime(mtime)}")# 获取创建时间(Windows)ctime = os.path.getctime(filepath)print(f"创建时间:{time.ctime(ctime)}")# 获取访问时间atime = os.path.getatime(filepath)print(f"最后访问时间:{time.ctime(atime)}")# 获取完整状态信息stat_info = os.stat(filepath)print(f"文件模式:{stat_info.st_mode}")print(f"文件inode:{stat_info.st_ino}")print(f"设备ID:{stat_info.st_dev}")print(f"硬链接数:{stat_info.st_nlink}")print(f"用户ID:{stat_info.st_uid}")print(f"组ID:{stat_info.st_gid}")
目录操作
import os# 创建目录dir_name = "my_folder"try: os.mkdir(dir_name) # 只能创建一级目录print(f"创建目录:{dir_name}")except FileExistsError:print(f"目录 {dir_name} 已存在")# 创建多级目录nested_dir = "a/b/c/d"os.makedirs(nested_dir, exist_ok=True) # exist_ok=True 表示如果存在也不报错print(f"创建多级目录:{nested_dir}")# 列出目录内容contents = os.listdir(".")print("当前目录内容:")for item in contents:print(f" {item}")# 切换当前目录original_dir = os.getcwd()print(f"当前在:{original_dir}")os.chdir("my_folder")print(f"切换到:{os.getcwd()}")os.chdir(original_dir) # 切回来print(f"回到:{os.getcwd()}")# 删除空目录os.rmdir("my_folder") # 只能删除空目录print(f"删除目录:my_folder")# 删除非空目录(需要shutil)import shutilshutil.rmtree("a") # 删除a及其所有内容print(f"删除目录树:a")
文件操作
import osimport shutil# 创建测试文件withopen("source.txt", "w") as f: f.write("这是源文件")# 重命名文件os.rename("source.txt", "renamed.txt")print("文件重命名:source.txt -> renamed.txt")# 复制文件shutil.copy2("renamed.txt", "copy.txt")print("文件复制:renamed.txt -> copy.txt")# 移动文件shutil.move("copy.txt", "moved.txt")print("文件移动:copy.txt -> moved.txt")# 删除文件os.remove("renamed.txt")os.remove("moved.txt")print("删除文件完成")# 创建符号链接(快捷方式)withopen("original.txt", "w") as f: f.write("原始文件")os.symlink("original.txt", "link.txt") # Windows需要管理员权限print("创建符号链接:link.txt -> original.txt")# 读取链接目标if os.path.islink("link.txt"): target = os.readlink("link.txt")print(f"链接指向:{target}")# 清理os.remove("original.txt")os.remove("link.txt")
附录2:pathlib详解
创建Path对象
from pathlib import Path# 创建Path对象的多种方式p1 = Path("test.txt") # 相对路径p2 = Path("/home/user/test.txt") # 绝对路径p3 = Path.home() / "test.txt"# 用户目录下的文件p4 = Path.cwd() / "data" / "config.json"# 当前目录下的文件print(f"相对路径对象:{p1}")print(f"绝对路径对象:{p2}")print(f"用户目录文件:{p3}")print(f"当前目录文件:{p4}")# Path对象的类型print(f"p1的类型:{type(p1)}") # <class 'pathlib.WindowsPath'># 获取路径的字符串表示p1_str = str(p1)print(f"字符串形式:{p1_str}")
Path对象的属性
from pathlib import Pathfilepath = Path("D:/projects/python-tutorial/data/config.json")# 基本属性print(f"完整路径:{filepath}")print(f"父目录:{filepath.parent}")print(f"文件名:{filepath.name}")print(f"文件名(无扩展):{filepath.stem}")print(f"扩展名:{filepath.suffix}")print(f"所有后缀:{filepath.suffixes}") # 对于.tar.gz这类文件# 路径组成部分print(f"盘符/根:{filepath.anchor}") # Windows的盘符,Linux的/print(f"所有父目录:{list(filepath.parents)}")# 路径属性print(f"是否为绝对路径:{filepath.is_absolute()}")print(f"是否为保留路径:{filepath.is_reserved()}") # Windows的保留设备名
路径操作
from pathlib import Path# 路径拼接(最优雅的特性)base = Path("D:/projects")docs = base / "docs" / "readme.txt"print(f"拼接结果:{docs}")# 等价于docs2 = Path(base, "docs", "readme.txt")print(f"另一种方式:{docs2}")# 获取相对路径absolute = Path("D:/projects/python-tutorial/test.txt")relative = absolute.relative_to("D:/projects")print(f"相对路径:{relative}") # python-tutorial/test.txt# 解析路径(去除.和..)complex_path = Path("./data/../config/./settings.json")resolved = complex_path.resolve()print(f"解析前:{complex_path}")print(f"解析后:{resolved}")# 判断路径关系path1 = Path("a/b/c")path2 = Path("a/b")print(f"path1是否在path2中:{path1.is_relative_to(path2)}")print(f"path2是否在path1中:{path2.is_relative_to(path1)}")# 通配符匹配print(f"匹配所有.txt:{Path('test.txt').match('*.txt')}")print(f"匹配所有文件:{Path('test.txt').match('*')}")
路径判断方法
from pathlib import Path# 创建测试文件test_file = Path("test.txt")test_file.touch() # 创建空文件test_dir = Path("test_dir")test_dir.mkdir(exist_ok=True)# 存在性判断print(f"test.txt是否存在:{test_file.exists()}")print(f"test_dir是否存在:{test_dir.exists()}")print(f"not_exist是否存在:{Path('not_exist').exists()}")# 类型判断print(f"test.txt是文件吗:{test_file.is_file()}")print(f"test.txt是目录吗:{test_file.is_dir()}")print(f"test_dir是目录吗:{test_dir.is_dir()}")# 特殊判断print(f"test.txt是符号链接吗:{test_file.is_symlink()}")print(f"test.txt是套接字吗:{test_file.is_socket()}")print(f"test.txt是FIFO吗:{test_file.is_fifo()}")print(f"test.txt是块设备吗:{test_file.is_block_device()}")print(f"test.txt是字符设备吗:{test_file.is_char_device()}")# 权限判断print(f"test.txt可读:{os.access(test_file, os.R_OK)}")print(f"test.txt可写:{os.access(test_file, os.W_OK)}")print(f"test.txt可执行:{os.access(test_file, os.X_OK)}")# 清理test_file.unlink()test_dir.rmdir()
目录操作
from pathlib import Path# 创建目录dir_path = Path("my_folder")dir_path.mkdir(exist_ok=True) # exist_ok=True 避免目录存在时报错print(f"创建目录:{dir_path}")# 创建多级目录nested = Path("a/b/c/d")nested.mkdir(parents=True, exist_ok=True) # parents=True 创建所有需要的父目录print(f"创建多级目录:{nested}")# 列出目录内容print("\n当前目录内容:")for item in Path(".").iterdir(): # iterdir() 返回生成器 type_symbol = "📁"if item.is_dir() else"📄"print(f" {type_symbol}{item.name}")# 使用通配符查找print("\n所有Python文件:")for py_file in Path(".").glob("*.py"):print(f" {py_file}")print("\n递归查找所有txt文件:")for txt_file in Path(".").rglob("*.txt"): # rglob = 递归globprint(f" {txt_file}")# 删除目录nested.rmdir() # 只能删除空目录Path("a/b/c").rmdir()Path("a/b").rmdir()Path("a").rmdir()print("\n删除多级目录完成")# 删除非空目录(需要shutil)import shutilif dir_path.exists(): shutil.rmtree(dir_path)print(f"删除目录树:{dir_path}")
文件操作
from pathlib import Path# 创建文件file_path = Path("example.txt")file_path.touch() # 创建空文件print(f"创建文件:{file_path}")# 写入文件file_path.write_text("这是写入的文本内容", encoding="utf-8")print("写入文本完成")# 读取文件content = file_path.read_text(encoding="utf-8")print(f"读取内容:{content}")# 二进制写入binary_path = Path("binary.bin")binary_path.write_bytes(b"\x00\x01\x02\x03")print("写入二进制数据完成")# 二进制读取binary_data = binary_path.read_bytes()print(f"读取二进制数据:{binary_data}")# 重命名文件new_path = file_path.with_name("renamed.txt") # 只改文件名file_path.rename(new_path)print(f"重命名为:{new_path}")# 修改后缀md_path = new_path.with_suffix(".md") # 改扩展名new_path.rename(md_path)print(f"修改后缀为:{md_path}")# 获取文件信息stat = md_path.stat()print(f"\n文件信息:")print(f" 大小:{stat.st_size} 字节")print(f" 修改时间:{stat.st_mtime}")print(f" 权限:{oct(stat.st_mode)[-3:]}")# 获取所有者和组(Unix)try:print(f" 所有者:{md_path.owner()}")print(f" 所属组:{md_path.group()}")except NotImplementedError:print(" 所有者信息:Windows不支持")# 修改权限md_path.chmod(0o644) # rw-r--r--print(f"修改权限后:{oct(md_path.stat().st_mode)[-3:]}")# 删除文件md_path.unlink() # 删除文件binary_path.unlink()print("\n删除文件完成")# 检查硬链接(Unix)hard_link = Path("hard_link.txt")ifnot hard_link.exists(): original = Path("original.txt") original.touch() original.link_to(hard_link) # 创建硬链接print(f"创建硬链接:{hard_link} -> {original}") original.unlink() hard_link.unlink()
Path对象的高级操作
from pathlib import Pathfrom datetime import datetimeclassEnhancedPath(Path):"""自定义Path类,添加额外功能"""def__new__(cls, *args, **kwargs):returnsuper().__new__(cls, *args, **kwargs)defmodified_time_str(self, format="%Y-%m-%d %H:%M:%S"):"""获取格式化的修改时间"""ifself.exists(): mtime = self.stat().st_mtimereturn datetime.fromtimestamp(mtime).strftime(format)return"文件不存在"defsize_str(self):"""获取人类可读的文件大小"""ifnotself.exists():return"文件不存在" size = self.stat().st_sizefor unit in ['B', 'KB', 'MB', 'GB']:if size < 1024:returnf"{size:.1f}{unit}" size /= 1024returnf"{size:.1f} TB"# 使用示例test_file = EnhancedPath("test.txt")test_file.touch()test_file.write_text("Hello" * 1000)print(f"文件名:{test_file.name}")print(f"修改时间:{test_file.modified_time_str()}")print(f"文件大小:{test_file.size_str()}")test_file.unlink()
附录3:常见问题
问题1:路径编码问题
import osfrom pathlib import Path# 问题:中文路径可能导致编码错误chinese_path = "D:/项目/数据/测试文件.txt"# 解决方案1:使用pathlib(自动处理编码)p = Path(chinese_path)if p.exists():print(f"文件存在:{p}")# 解决方案2:使用原始字符串raw_path = r"D:\项目\数据\测试文件.txt"# 解决方案3:明确指定编码import sysif sys.platform == 'win32':# Windows需要处理编码import ctypes kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleOutputCP(65001) # UTF-8
问题2:权限问题
import osfrom pathlib import Pathdefsafe_write_file(filepath, content):"""安全的文件写入(处理权限问题)""" filepath = Path(filepath)try:# 尝试直接写入 filepath.write_text(content, encoding='utf-8')print(f"成功写入:{filepath}")except PermissionError:print(f"权限不足,无法写入:{filepath}")# 尝试写入用户目录 fallback = Path.home() / "temp" / filepath.name fallback.parent.mkdir(exist_ok=True) fallback.write_text(content, encoding='utf-8')print(f"已写入备用位置:{fallback}")except Exception as e:print(f"写入失败:{e}")
问题3:跨平台兼容性
import osfrom pathlib import Pathimport platformdefget_app_data_dir(app_name):"""获取应用程序数据目录(跨平台)""" system = platform.system()if system == "Windows":# Windows: %APPDATA%\app_name base = Path(os.environ.get('APPDATA', Path.home()))elif system == "Darwin": # macOS# macOS: ~/Library/Application Support/app_name base = Path.home() / "Library" / "Application Support"else: # Linux 和其他 Unix# Linux: ~/.local/share/app_name base = Path.home() / ".local" / "share" app_dir = base / app_name app_dir.mkdir(parents=True, exist_ok=True)return app_dir# 使用示例app_dir = get_app_data_dir("myapp")print(f"应用数据目录:{app_dir}")