当前位置:首页>python>Python路径操作:os vs pathlib 完全对比

Python路径操作:os vs pathlib 完全对比

  • 2026-09-08 18:08:03
Python路径操作:os vs pathlib 完全对比

路径是文件或文件夹在计算机中的"地址"。就像家庭地址一样,路径告诉计算机去哪里找某个文件。

类比举例:

生活中的地址:中国 → 北京市 → 海淀区 → 中关村大街 → 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
    (当前目录下的report.pdf)
  • ../docs/readme.txt
    (上级目录的docs文件夹里的readme.txt)
  • data/images/photo.jpg
    (当前目录下data/images里的photo.jpg)

特殊符号含义

  • .
     表示当前目录
  • ..
     表示上级目录

1. Python的两种路径处理方式

Python主要提供了两种处理路径的方式:

  1. 传统方式:os.path模块(Python诞生就有了)
  2. 现代方式:pathlib模块(Python 3.4引入)

os.path方式的特点

  • 基于字符串操作
  • 函数式编程风格
  • 性能略好
  • 兼容Python 2

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}")

作者简介:码上工坊,探索用编程为己赋能,定期分享编程知识和项目实战经验。持续学习、适应变化、记录点滴、复盘反思、成长进步。

重要提示:本文主要是记录自己的学习与实践过程,所提内容或者观点仅代表个人意见,只是我以为的,不代表完全正确,欢迎交流讨论。

最新文章

随机文章