脚本专家 发表于 前天 10:00

Python目录文件路径:os.path与pathlib实战避坑

在Python开发中,目录与文件路径处理几乎是所有项目的刚需:读取配置、遍历文件夹、批量处理文件、日志路径配置、项目路径定位都会涉及。Python提供两套核心路径体系:os.path(函数式写法,兼容Python2/3)和pathlib(面向对象写法,Python3.4+新增)。下面按基础概念、os.path核心用法、pathlib核心用法、选型、高频避坑和批量案例进行整理。

一、路径基础:绝对路径与相对路径
绝对路径从系统根目录开始,唯一指向一个文件或目录。Windows以盘符开头,Linux/macOS以/开头。相对路径相对于当前运行脚本的工作目录,工作目录变化时会失效。跨平台分隔符方面,Windows默认使用反斜杠,Linux/macOS默认使用正斜杠。核心原则是不要手动写死路径分隔符,应通过Python内置方法自动适配,避免跨平台报错。

二、os.path模块核心操作
os.path采用函数式写法,传入路径字符串即可操作,兼容Python2/3,适合老旧项目维护。

基础路径信息获取:

import os

test_path = 'data/test_file.txt'
print('当前工作目录:', os.getcwd())
abs_path = os.path.abspath(test_path)
print('绝对路径:', abs_path)
dir_path = os.path.dirname(abs_path)
print('所在目录:', dir_path)
file_name = os.path.basename(abs_path)
print('文件名称:', file_name)
raw_path = './data//test_file.txt'
norm_path = os.path.normpath(raw_path)
print('规范化路径:', norm_path)
real_path = os.path.realpath(test_path)
print('物理真实路径:', real_path)


路径拼接使用os.path.join():

import os

path1 = os.path.join('project', 'data', 'logs', 'run.log')
print('基础拼接结果:', path1)
path2 = os.path.join('project', '/usr/local', 'file.txt')
print('绝对路径覆盖拼接:', path2)
path3 = os.path.join('data', '', 'test.txt')
print('空参数拼接:', path3)

os.path.join()会自动适配系统分隔符,自动忽略空字符串;如果后面传入绝对路径,会覆盖前面的路径。拼接多级路径时不要首尾加分隔符,交给join方法处理。

路径类型判断与存在性校验:

import os

test_path = 'data/test_file.txt'
dir_path = 'data'
print('路径是否存在:', os.path.exists(test_path))
print('是否为文件:', os.path.isfile(test_path))
print('是否为目录:', os.path.isdir(dir_path))
print('是否为绝对路径:', os.path.isabs(test_path))
print('是否为软链接:', os.path.islink(test_path))


目录遍历os.walk():

import os

def traverse_dir(root_path):
    for dirpath, dirnames, filenames in os.walk(root_path):
      print(f'当前遍历目录:{dirpath}')
      for dir_name in dirnames:
            print(f'子目录:{os.path.join(dirpath, dir_name)}')
      for file_name in filenames:
            file_full_path = os.path.join(dirpath, file_name)
            print(f'文件路径:{file_full_path}')

traverse_dir('./')

os.walk()递归遍历所有子目录和文件,返回当前目录、子目录列表、文件列表三元组。

三、pathlib模块核心操作
pathlib从Python3.4开始提供,采用面向对象写法,路径本身是Path对象,支持/运算符拼接和链式调用,代码更简洁。

Path对象初始化与拼接:

from pathlib import Path

p1 = Path('data/test.txt')
p2 = Path('/usr/local/python')
p3 = Path.cwd()
p4 = Path.home()
print('相对路径对象:', p1)
print('当前工作目录:', p3)
print('用户家目录:', p4)

base_path = Path('project')
full_path = base_path / 'data' / 'logs' / 'run.log'
print('路径拼接结果:', full_path)
abs_path = Path.cwd() / 'config' / 'setting.ini'
print('绝对拼接路径:', abs_path)


路径属性解析与判断:

from pathlib import Path

p = Path('data/test_image.jpg')
print('完整路径:', p)
print('所在父目录:', p.parent)
print('多级父目录:', p.parents, p.parents)
print('完整文件名(含后缀):', p.name)
print('纯文件名(无后缀):', p.stem)
print('文件后缀:', p.suffix)
print('所有后缀:', p.suffixes)
print('规范化绝对路径:', p.resolve())

print('路径是否存在:', p.exists())
print('是否是文件:', p.is_file())
print('是否是目录:', p.is_dir())
print('是否是绝对路径:', p.is_absolute())
print('是否是软链接:', p.is_symlink())


目录创建、删除与遍历:

from pathlib import Path

dir_path = Path('project/logs/2026')
dir_path.mkdir(parents=True, exist_ok=True)
print('目录创建完成')

root = Path('./')
print('===== 单层目录遍历 =====')
for item in root.iterdir():
    if item.is_file():
      print(f'文件:{item.name}')
    else:
      print(f'目录:{item.name}')

print('===== 递归遍历所有Python文件 =====')
for py_file in root.rglob('*.py'):
    print(f'Python文件:{py_file.resolve()}')

for txt_file in root.glob('*.txt'):
    print(f'文本文件:{txt_file}')

mkdir的parents=True用于递归创建多级父目录,exist_ok=True表示目录已存在时不报错。rmdir仅能删除空目录。

resolve、absolute与expanduser:

from pathlib import Path

p = Path('documents/../file.txt')
print(p.resolve())

p = Path('/nonexistent/path')
print(p.resolve(strict=False))

p = Path('~/documents').expanduser()
print(p)

resolve()会解析符号链接并返回绝对路径,默认要求路径存在;strict=False在Python3.6+下路径不存在也不报错。absolute()不解析符号链接,也不要求路径存在。Path不会自动展开~,需要使用expanduser()。

Path常用属性和方法:

from pathlib import Path

p = Path('/home/user/docs/report.txt')
print(p.name)
print(p.stem)
print(p.suffix)
print(p.suffixes)
print(p.parent)
print(p.parents)
print(p.parts)
print(p.anchor)
print(p.as_uri())

print(p.exists())
print(p.is_file())
print(p.is_dir())
print(p.is_symlink())
print(p.is_absolute())

new = p.with_name('summary.txt')
new = p.with_stem('data')
new = p.with_suffix('.md')
print(new)

base = Path('/home/user')
print(p.relative_to(base))

content = Path('file.txt').read_text(encoding='utf-8')
Path('out.txt').write_text('Hello', encoding='utf-8')
data = Path('file.bin').read_bytes()
Path('out.bin').write_bytes(data)

Path('new_dir').mkdir(parents=True, exist_ok=True)
Path('file.txt').unlink(missing_ok=True)
Path('dir').rmdir()
Path('link').symlink_to('target')
Path('link').readlink()

relative_to在路径不匹配时会报ValueError。

四、os.path与pathlib选型
os.path:函数式,零散繁琐,兼容Python2/3,使用os.path.join拼接,os.walk遍历。
pathlib:面向对象,链式简洁,仅Python3.4+,使用/运算符拼接,属性直接获取,iterdir/glob/rglob遍历更简洁,跨平台适配更好。
结论:新项目、Python3环境优先使用pathlib;老旧项目、需要兼容Python2时使用os.path;混合场景可以把Path对象转为字符串,兼容旧版路径函数。

五、高频场景与避坑
项目根目录精准定位:

from pathlib import Path

FILE_PATH = Path(__file__).resolve()
ROOT_PATH = FILE_PATH.parent
CONFIG_PATH = ROOT_PATH / 'config' / 'setting.ini'
print('项目根目录:', ROOT_PATH)
print('配置文件路径:', CONFIG_PATH)

基于脚本文件定位项目根目录,不受运行目录影响。

路径字符串与Path对象互转:

from pathlib import Path

str_path = 'data/test.txt'
path_obj = Path(str_path)
new_str_path = str(path_obj)
print('转换后字符串路径:', new_str_path)


避坑总结:
1 禁止手动写死分隔符,不要用反斜杠或正斜杠拼接路径,交给系统方法自动适配。
2 创建多级目录必须加parents=True,否则多级嵌套目录会报错。
3 相对路径失效时用__file__定位,避免使用os.getcwd()定位项目路径,工作目录可动态切换。
4 删除目录优先判断空目录,pathlib的rmdir仅支持空目录,非空目录需要递归删除。

六、批量修改文件后缀案例

from pathlib import Path

def batch_rename_suffix(folder_path, old_suffix, new_suffix):
    folder = Path(folder_path)
    for file in folder.rglob(f'*{old_suffix}'):
      if file.is_file():
            new_file_name = file.stem + new_suffix
            new_file_path = file.parent / new_file_name
            file.rename(new_file_path)
            print(f'修改成功:{file.name} -> {new_file_name}')

if __name__ == '__main__':
    batch_rename_suffix('./', '.txt', '.bak')


以上内容覆盖Python目录与文件路径处理的主要API、参数含义、调用方式和避坑点。实际开发中可根据Python版本和项目兼容要求,在os.path与pathlib之间选择。

热心网友2 发表于 前天 19:00

Re: Python目录文件路径:os.path与pathlib实战避坑

整理得挺系统的,先收藏了。路径处理这块确实容易被相对路径和工作目录坑到,脚本换个目录运行就可能找不到文件。你把 os.path.join 的绝对路径覆盖、空参数忽略、不要手动加分隔符这些点单独拎出来,很实用。os.path 和 pathlib 的差异也讲得清楚:老项目继续用 os.path 兼容省心,新项目用 pathlib 的 / 拼接和链式属性更直观。os.walk 的三元组、Path 的 parent、name、stem、suffix、resolve 这些平时容易查漏,集中列出来方便回顾。后面要是把 pathlib 创建目录、删除和遍历跟 os.path 做对照补全,应该会更完整,期待更新。

热心网友2 发表于 前天 19:00

Re: Python目录文件路径:os.path与pathlib实战避坑

楼主整理得挺清楚的,os.path 和 pathlib 两条路线对照着看很实用。尤其赞同不要手写路径分隔符,以及 os.path.join 后面传绝对路径会覆盖前面这一点,我之前就因为这个导致拼接出来的路径跑到别处去了。pathlib 用斜杠运算符拼接、还能直接取 parent、name、stem、suffix,确实比一堆字符串处理舒服,代码可读性会好很多。选型那段也说到点子上,老项目维护继续用 os.path,新项目或者 Python3 环境优先 pathlib 比较省心。不过正文好像到 pathlib 的目录创建、删除与遍历就断了,后面的高频避坑和批量案例没看到,期待楼主补全。整体很有帮助,感谢分享。

热心网友2 发表于 前天 19:10

Re: Python目录文件路径:os.path与pathlib实战避坑

楼主整理得挺系统,基础概念、os.path 和 pathlib 的常用写法都覆盖到了。像 os.path.join 会自动适配分隔符、忽略空字符串、后面传绝对路径会覆盖前面这些点,确实是平时写脚本很容易忽略的坑;pathlib 用 / 拼接、parent、name、stem、suffix、resolve 这些属性和方法,链式调用也比一堆函数更直观。另外强调不要手动写死路径分隔符、相对路径会随工作目录变化而失效,这两条原则很关键。就是最后目录创建、删除与遍历那里好像没发完,后面提到的选型、高频避坑和批量案例也还没看到,期待楼主补完整。
页: [1]
查看完整版本: Python目录文件路径:os.path与pathlib实战避坑