【Python基础】Python路径操作全解析:os.path、glob与pathlib从入门到精通

目录

  • Python路径操作全解析:os.path、glob与pathlib从入门到精通
    • 一、路径操作的必要性与背景
    • [二、os.path 模块:传统路径处理](#二、os.path 模块:传统路径处理)
      • [1. 设计哲学](#1. 设计哲学)
      • [2. 核心函数详解](#2. 核心函数详解)
        • [(1) 路径拼接](#(1) 路径拼接)
        • [(2) 路径信息获取](#(2) 路径信息获取)
        • [(3) 路径类型判断](#(3) 路径类型判断)
        • [(4) 路径解析](#(4) 路径解析)
      • [3. os.path 的局限性](#3. os.path 的局限性)
    • [三、glob 模块:路径模式匹配](#三、glob 模块:路径模式匹配)
      • [1. 基本用法](#1. 基本用法)
      • [2. glob 的高级模式匹配](#2. glob 的高级模式匹配)
      • [3. glob 的参数](#3. glob 的参数)
      • [4. glob 的应用场景](#4. glob 的应用场景)
    • [四、pathlib 模块:现代路径处理](#四、pathlib 模块:现代路径处理)
      • [1. 设计哲学](#1. 设计哲学)
      • [2. 基本用法](#2. 基本用法)
        • [(1) 创建Path对象](#(1) 创建Path对象)
        • [(2) 路径操作](#(2) 路径操作)
        • [(3) 遍历目录](#(3) 遍历目录)
        • [(4) 文件操作](#(4) 文件操作)
        • [(5) 路径解析与规范化](#(5) 路径解析与规范化)
        • [(6) 文件权限操作](#(6) 文件权限操作)
        • [(7) 递归遍历与文件操作](#(7) 递归遍历与文件操作)
        • [(8) 路径安全处理](#(8) 路径安全处理)
      • [3. pathlib 与 os.path 对比](#3. pathlib 与 os.path 对比)
    • 五、补充其他路径相关模块
    • 六、各个方法之间的对比
      • [1. 路径操作的演进](#1. 路径操作的演进)
      • [2. 模块对比表](#2. 模块对比表)
      • [3. 选择建议](#3. 选择建议)
      • [4. 代码风格对比](#4. 代码风格对比)
      • [5. EAFP vs LBYL 风格](#5. EAFP vs LBYL 风格)
    • 七、高级技巧与实战案例
      • [1. 批量修改文件扩展名](#1. 批量修改文件扩展名)
      • [2. 构建目录树统计器](#2. 构建目录树统计器)
      • [3. 路径安全处理](#3. 路径安全处理)
      • [4. 跨平台路径处理](#4. 跨平台路径处理)
      • [5. 文件处理工作流](#5. 文件处理工作流)
      • [6. 安全路径操作函数](#6. 安全路径操作函数)
    • 八、常见问题与解决
      • [1. 为什么在Windows上使用pathlib时路径显示为反斜杠?](#1. 为什么在Windows上使用pathlib时路径显示为反斜杠?)
      • [2. 如何处理路径中的空格和特殊字符?](#2. 如何处理路径中的空格和特殊字符?)
      • [3. 如何在不同系统间共享路径?](#3. 如何在不同系统间共享路径?)
    • 九、总结与建议

Python路径操作全解析:os.path、glob与pathlib从入门到精通

一、路径操作的必要性与背景

在文件系统操作中,路径处理是基础且关键的环节。不同操作系统使用不同的路径分隔符(Windows用\,Unix-like系统用/),手动处理路径容易导致代码不可移植。Python提供了多个模块来解决这个问题,其中最常用的是os.pathglobpathlib

二、os.path 模块:传统路径处理

1. 设计哲学

  • 过程式路径处理:基于字符串的函数集合
  • 典型特征:需要组合多个函数完成复杂操作,路径作为普通字符串处理

2. 核心函数详解

(1) 路径拼接
python 复制代码
import os
# 传统方式
path = os.path.join("/home/user", "documents", "file.txt")
# 结果:/home/user/documents/file.txt
(2) 路径信息获取
python 复制代码
# 获取最后修改时间
mtime = os.path.getmtime("file.txt")  # 返回纪元秒数

# 获取文件大小
size = os.path.getsize("file.txt")  # 返回字节数

# 获取路径的ctime
ctime = os.path.getctime("file.txt")  # Unix上是元数据最后修改时间,Windows上是创建时间
(3) 路径类型判断
python 复制代码
# 判断是否是绝对路径
is_abs = os.path.isabs("/home/user")  # True

# 判断是否是文件
is_file = os.path.isfile("/home/user/file.txt")  # True/False

# 判断是否是目录
is_dir = os.path.isdir("/home/user")  # True/False

# 判断是否是符号链接
is_link = os.path.islink("/home/user/link")  # True/False

# 判断是否是挂载点
is_mount = os.path.ismount("/home")  # True/False
(4) 路径解析
python 复制代码
# 分离路径的目录和文件名
directory, filename = os.path.split("/home/user/file.txt")
# directory: /home/user, filename: file.txt

# 获取文件名
filename = os.path.basename("/home/user/file.txt")  # file.txt

# 获取目录名
dirname = os.path.dirname("/home/user/file.txt")  # /home/user

# 分离文件名和扩展名
name, ext = os.path.splitext("report.txt")
# name: report, ext: .txt

3. os.path 的局限性

  • 函数式风格:需要频繁调用多个函数,代码零散
  • 字符串处理:路径作为字符串处理,容易出错
  • 平台差异:需要手动处理路径分隔符差异
  • 状态无感知:无状态操作,不跟踪当前工作目录

三、glob 模块:路径模式匹配

1. 基本用法

python 复制代码
import glob

# 查找所有txt文件
txt_files = glob.glob("*.txt")
# 结果:['file1.txt', 'file2.txt', ...]

# 查找所有子目录下的txt文件
all_txt_files = glob.glob("**/*.txt", recursive=True)

2. glob 的高级模式匹配

python 复制代码
import glob

# 匹配以数字开头的文件
num_files = glob.glob("[0-9]*.txt")

# 匹配特定扩展名
pdf_files = glob.glob("*.pdf")

# 匹配多个模式
files = glob.glob("*.txt|*.csv", recursive=True)  # 仅在Python 3.10+支持

3. glob 的参数

python 复制代码
# GLOB_MARK: 在每个返回的项目中加一个斜线
files = glob.glob("*.txt", flags=glob.GLOB_MARK)

# GLOB_NOSORT: 按照文件在目录中出现的原始顺序返回
files = glob.glob("*.txt", flags=glob.GLOB_NOSORT)

# GLOB_NOCHECK: 如果没有文件匹配则返回用于搜索的模式
files = glob.glob("*.nonexistent", flags=glob.GLOB_NOCHECK)

# GLOB_ONLYDIR: 仅返回与模式匹配的目录项
dirs = glob.glob("*.dir", flags=glob.GLOB_ONLYDIR)

4. glob 的应用场景

  • 遍历目录中的特定类型文件
  • 检索符合特定命名模式的文件
  • 与os.path结合进行高级路径处理

四、pathlib 模块:现代路径处理

1. 设计哲学

  • 面向对象路径操作:路径即对象(Path实例)
  • 核心优势
    • 支持链式方法调用
    • 自动处理平台差异
    • 集成文件系统操作

2. 基本用法

(1) 创建Path对象
python 复制代码
from pathlib import Path

# 从字符串创建
file_path = Path("data/report.txt")

# 从其他Path对象创建
base_path = Path("/home/user")
data_path = base_path / "data"  # /home/user/data

# 从当前工作目录创建
cwd = Path.cwd()  # 当前工作目录

# 从主目录创建
home = Path.home()  # 主目录
(2) 路径操作
python 复制代码
# 路径拼接(使用/运算符)
path = Path("/home") / "user" / "data" / "file.txt"

# 获取文件名
filename = path.name  # file.txt

# 获取扩展名
ext = path.suffix  # .txt

# 获取父目录
parent = path.parent  # /home/user/data

# 获取文件大小
size = path.stat().st_size

# 获取最后修改时间
mtime = path.stat().st_mtime

# 判断文件是否存在
exists = path.exists()

# 判断是否是文件
is_file = path.is_file()

# 判断是否是目录
is_dir = path.is_dir()
(3) 遍历目录
python 复制代码
# 查找当前目录下所有txt文件
txt_files = list(Path.cwd().glob("*.txt"))

# 查找所有子目录下的txt文件
all_txt_files = list(Path.cwd().rglob("*.txt"))
(4) 文件操作
python 复制代码
# 读取文件内容
content = Path("file.txt").read_text(encoding="utf-8")

# 写入文件
Path("new_file.txt").write_text("Hello, World!", encoding="utf-8")

# 创建目录
Path("new_dir").mkdir(exist_ok=True)

# 重命名文件
Path("old.txt").rename("new.txt")

# 删除文件
Path("file.txt").unlink()
(5) 路径解析与规范化
python 复制代码
from pathlib import Path

# 获取绝对路径
absolute_path = Path("relative/path").resolve()

# 处理符号链接
resolved_path = Path("symlink").resolve()

# 获取相对于某个路径的相对路径
relative_path = Path("current_dir/file.txt").relative_to(Path("current_dir"))
(6) 文件权限操作
python 复制代码
from pathlib import Path

p = Path("file.txt")

# 获取文件权限
permissions = p.stat().st_mode

# 更改文件权限
p.chmod(0o644)  # 读写权限给用户,读权限给组和其他用户

# 获取文件所有者
owner = p.owner()
group = p.group()
(7) 递归遍历与文件操作
python 复制代码
from pathlib import Path

# 递归遍历所有文件
for file in Path.cwd().rglob("*"):
    if file.is_file():
        print(f"文件: {file}")
    else:
        print(f"目录: {file}")

# 读取所有文本文件
text_files = [f for f in Path.cwd().rglob("*.txt") if f.is_file()]
for file in text_files:
    print(file.read_text(encoding="utf-8"))
(8) 路径安全处理
python 复制代码
from pathlib import Path

def safe_path(path: str) -> Path:
    """确保路径是安全的,不包含恶意路径"""
    p = Path(path).resolve()
    # 确保路径在安全目录内
    if not p.is_relative_to(Path.cwd()):
        raise ValueError("路径超出安全范围")
    return p

# 示例
try:
    safe_file = safe_path("../malicious/file.txt")
except ValueError as e:
    print(f"安全错误: {e}")

3. pathlib 与 os.path 对比

功能描述 os.path 方法 pathlib 方法
路径拼接 os.path.join() / 运算符或 .joinpath()
获取文件名 os.path.basename() .name 属性
获取父目录 os.path.dirname() .parent 属性
获取扩展名 os.path.splitext()[1] .suffix 属性
判断文件存在 os.path.exists() .exists() 方法
判断是否为文件 os.path.isfile() .is_file() 方法
判断是否为目录 os.path.isdir() .is_dir() 方法
获取绝对路径 os.path.abspath() .resolve() 方法
路径规范化 os.path.normpath() .resolve(strict=False)
相对路径转换 os.path.relpath() .relative_to() 方法
获取文件大小 os.path.getsize() .stat().st_size
获取最后修改时间 os.path.getmtime() .stat().st_mtime
创建目录 os.mkdir() .mkdir(parents=True)
删除文件 os.remove() .unlink()
删除空目录 os.rmdir() .rmdir()

五、补充其他路径相关模块

1. shutil 模块:高级文件操作

设计哲学
  • 高阶文件操作:提供比os更高层次的文件操作函数
  • 核心优势:简化文件复制、移动、归档等复杂操作
常用函数详解
python 复制代码
import shutil
from pathlib import Path

# 复制文件(保留元数据)
shutil.copy("source.txt", "destination.txt")

# 复制文件(保留所有元数据,包括时间戳)
shutil.copy2("source.txt", "destination2.txt")

# 递归复制目录
shutil.copytree("source_dir", "destination_dir")

# 移动/重命名文件或目录
shutil.move("old_name.txt", "new_name.txt")

# 递归删除目录(包括其内容)
shutil.rmtree("directory_to_delete")

# 创建归档文件(如zip、tar等)
shutil.make_archive("archive", "zip", "directory_to_compress")

# 解压归档文件
shutil.unpack_archive("archive.zip", "extract_dir")
实战案例:备份目录
python 复制代码
def backup_directory(src_dir, backup_dir):
    """创建目录的备份"""
    backup_path = Path(backup_dir) / Path(src_dir).name
    if backup_path.exists():
        shutil.rmtree(backup_path)
    shutil.copytree(src_dir, backup_path)
    print(f"已备份到: {backup_path}")

2. tempfile 模块:安全临时文件操作

设计哲学
  • 安全创建临时文件:避免与其他进程的临时文件冲突
  • 自动清理:默认在文件对象关闭后自动删除
常用函数详解
python 复制代码
import tempfile
import os

# 创建临时文件(不自动删除)
with tempfile.NamedTemporaryFile(delete=False) as tmp:
    tmp.write(b"Temporary content")
    temp_path = tmp.name

# 读取临时文件
with open(temp_path, 'r') as f:
    print(f.read())

# 删除临时文件
os.unlink(temp_path)

# 创建临时目录
temp_dir = tempfile.mkdtemp()
print(f"临时目录: {temp_dir}")
# 使用后删除
shutil.rmtree(temp_dir)

# 临时文件对象(自动删除)
with tempfile.NamedTemporaryFile() as tmp:
    tmp.write(b"Auto-deleted content")
    print("临时文件已创建,将在退出时自动删除")

3. fnmatch 模块:文件名模式匹配

设计哲学
  • 轻量级文件名匹配:专注于单个文件名的匹配,比glob更轻量
  • 与glob相似但更简单:适合不需要递归匹配的场景
常用函数详解
python 复制代码
import fnmatch

# 检查文件名是否匹配模式(不区分大小写)
print(fnmatch.fnmatch("report.pdf", "*.pdf"))  # True
print(fnmatch.fnmatch("Report.PDF", "*.pdf"))  # True (默认不区分大小写)

# 区分大小写匹配
print(fnmatch.fnmatchcase("Report.PDF", "*.pdf"))  # False

# 遍历目录匹配文件
for file in os.listdir("."):
    if fnmatch.fnmatch(file, "*.txt"):
        print(f"匹配的文本文件: {file}")
实战案例:过滤文件列表
python 复制代码
def filter_files(file_list, pattern):
    """过滤文件列表,返回匹配模式的文件"""
    return [f for f in file_list if fnmatch.fnmatch(f, pattern)]

六、各个方法之间的对比

1. 路径操作的演进

  • 传统方式:字符串拼接(不推荐)
  • 过渡方式:os.path(字符串处理,功能有限)
  • 现代方式:pathlib(面向对象,代码简洁,跨平台)
  • 高级操作:shutil(高级文件操作)
  • 模式匹配:glob(高效文件匹配)
  • 安全操作:tempfile(安全临时文件)

2. 模块对比表

模块/库 适用场景 优点 缺点 推荐度
os 基础系统交互 通用,广泛使用 代码不直观 ★★★☆
os.path 路径字符串处理 与os配合 仍然基于字符串 ★★☆
pathlib 现代路径操作 面向对象,代码简洁,跨平台 需要Python 3.4+ ★★★★
glob 模式匹配文件 简单高效的文件匹配 仅用于匹配 ★★★★
shutil 高级文件操作 简化复制、移动、归档 仅用于操作 ★★★★
tempfile 临时文件 安全创建临时文件 仅用于临时文件 ★★★☆
fnmatch 文件名匹配 轻量级匹配 仅用于单个文件名 ★★★

3. 选择建议

场景 推荐工具 说明
基础路径处理 pathlib 代码简洁,跨平台
文件复制/移动 shutil 简化高级文件操作
文件模式匹配 glob 高效查找匹配文件
临时文件 tempfile 安全创建临时文件
文件名匹配 fnmatch 轻量级匹配,适合单个文件
旧代码维护 os.path 保持与现有代码一致

4. 代码风格对比

os.path 风格 (传统)

python 复制代码
import os

file_path = os.path.join(os.path.dirname(__file__), "data", "report.txt")
if os.path.exists(file_path) and os.path.isfile(file_path):
    with open(file_path, 'r') as f:
        content = f.read()

pathlib 风格 (现代)

python 复制代码
from pathlib import Path

file_path = Path(__file__).parent / "data" / "report.txt"
if file_path.exists() and file_path.is_file():
    content = file_path.read_text(encoding="utf-8")

5. EAFP vs LBYL 风格

EAFP (Easier to Ask for Forgiveness than Permission)

python 复制代码
from pathlib import Path

try:
    content = Path("file.txt").read_text()
    print("文件存在且可读取")
except FileNotFoundError:
    print("文件不存在")
except PermissionError:
    print("没有读取权限")

LBYL (Look Before You Leap)

python 复制代码
from pathlib import Path

path = Path("file.txt")
if path.exists() and path.is_file() and path.is_readable():
    content = path.read_text()
else:
    print("文件不存在或不可读")

七、高级技巧与实战案例

1. 批量修改文件扩展名

python 复制代码
# 使用pathlib
from pathlib import Path

for p in Path("reports").glob("*.txt"):
    p.rename(p.with_suffix(".md"))

# 使用os.path
import os
for root, _, files in os.walk("reports"):
    for f in files:
        if f.endswith(".txt"):
            old_path = os.path.join(root, f)
            new_path = os.path.splitext(old_path)[0] + ".md"
            os.rename(old_path, new_path)

2. 构建目录树统计器

python 复制代码
from pathlib import Path

def analyze_dir(path: Path):
    return {
        "dir_count": sum(1 for _ in path.rglob("*/")),
        "file_count": sum(1 for _ in path.rglob("*") if _.is_file())
    }

result = analyze_dir(Path.cwd())
print(f"目录数: {result['dir_count']}, 文件数: {result['file_count']}")

3. 路径安全处理

python 复制代码
from pathlib import Path

def safe_path(path: str) -> Path:
    """确保路径是安全的,不包含恶意路径"""
    p = Path(path).resolve()
    if not p.is_absolute():
        p = p.resolve()
    return p

# 示例
safe_file = safe_path("../malicious/file.txt")
print(safe_file)  # 将转换为绝对路径,避免目录遍历攻击

4. 跨平台路径处理

python 复制代码
from pathlib import Path

# 跨平台路径拼接
path = Path("data") / "images" / "photo.jpg"

# 获取平台特定的分隔符
separator = Path.sep  # '/' on Unix, '\' on Windows

# 转换为字符串(自动处理平台差异)
str_path = str(path)  # 在Windows上会是"data\images\photo.jpg"

5. 文件处理工作流

python 复制代码
from pathlib import Path
import shutil
import glob

def process_files(source_dir, destination_dir, pattern="*.txt"):
    """处理匹配模式的文件,复制到目标目录"""
    source = Path(source_dir)
    dest = Path(destination_dir)
    
    # 创建目标目录
    dest.mkdir(parents=True, exist_ok=True)
    
    # 处理所有匹配的文件
    for file in source.glob(pattern):
        if file.is_file():
            # 创建安全的文件名
            safe_name = file.name.replace(" ", "_")
            dest_file = dest / safe_name
            
            # 复制文件(保留元数据)
            shutil.copy2(file, dest_file)
            
            # 添加处理日志
            print(f"已处理: {file} -> {dest_file}")
    
    print(f"共处理 {len(list(source.glob(pattern)))} 个文件")

# 使用示例
process_files("data/source", "data/processed", "*.txt")

6. 安全路径操作函数

python 复制代码
from pathlib import Path
import os

def safe_file_operation(file_path, operation, *args, **kwargs):
    """安全执行文件操作,防止路径遍历攻击"""
    # 获取当前工作目录的绝对路径
    base_path = Path.cwd().resolve()
    
    # 解析目标路径并检查是否在安全范围内
    target_path = Path(file_path).resolve()
    if not target_path.is_relative_to(base_path):
        raise ValueError("路径超出安全范围,可能包含目录遍历攻击")
    
    # 执行操作
    try:
        return operation(target_path, *args, **kwargs)
    except FileNotFoundError as e:
        print(f"文件未找到: {file_path}")
        raise e
    except PermissionError as e:
        print(f"权限错误: {file_path}")
        raise e

# 使用示例
def read_file_safe(file_path):
    return safe_file_operation(file_path, Path.read_text)

content = read_file_safe("data/file.txt")

八、常见问题与解决

1. 为什么在Windows上使用pathlib时路径显示为反斜杠?

  • 在Python字符串中,反斜杠是转义字符
  • 解决方案:使用原始字符串或正斜杠
python 复制代码
# 正确方式
p = Path(r"C:\Users\user")  # 原始字符串
p = Path("C:/Users/user")   # 正斜杠

# 错误方式
p = Path("C:\Users\user")   # 会被解释为C:Usersuser

2. 如何处理路径中的空格和特殊字符?

  • pathlib会自动处理特殊字符,无需额外处理
python 复制代码
p = Path("my folder/file with spaces.txt")
# 无需额外转义,pathlib会正确处理

3. 如何在不同系统间共享路径?

  • 使用pathlib的as_posix()方法
python 复制代码
path = Path("data/file.txt")
posix_path = path.as_posix()  # 'data/file.txt' (Unix风格)
windows_path = path.as_posix().replace("/", "\\")  # 'data\file.txt' (Windows风格)

九、总结与建议

  1. 新项目首选pathlib:它是Python 3.4+的标准库,提供了面向对象的路径处理方式,代码更简洁、可读性更好。
  2. 避免硬编码路径分隔符:使用os.path.join()或pathlib的/运算符,避免使用硬编码的'/'或''。
  3. 使用glob进行模式匹配:特别是当需要遍历特定模式的文件时,glob与pathlib结合使用效果最佳。
  4. 处理路径安全 :在处理用户输入的路径时,使用.resolve()确保路径的安全性,避免目录遍历攻击。
  5. 考虑EAFP风格:Python社区推荐EAFP(先尝试,再捕获异常)风格,比LBYL(先检查,再操作)更简洁。
  6. 逐步迁移:如果维护旧代码,可以逐步将os.path代码迁移到pathlib,提高代码质量和可维护性。
相关推荐
这里有鱼汤3 小时前
3步用Python识别MACD背驰,避免80%追涨杀跌陷阱,建议收藏
后端·python
程序员爱钓鱼3 小时前
Python编程实战 · 基础入门篇 | Python能做什么
后端·python·github
_poplar_3 小时前
15 【C++11 新特性】统一的列表初始化和变量类型推导
开发语言·数据结构·c++·git·算法
lly2024063 小时前
Ruby Socket 编程
开发语言
i学长的猫3 小时前
Ruby小白学习路线
开发语言·学习·ruby
生信小窝4 小时前
068B-基于R语言平台Biomod2集成模型的物种分布模型构建和数据可视化教程【2027】
开发语言·信息可视化·r语言
一车小面包4 小时前
Transformers中从 logits 本质到问答系统中的字符定位机制
pytorch·python·深度学习
战族狼魂4 小时前
基于python+Java的二手车与奔驰销量数据可视化平台
java·数据库·python
Goboy4 小时前
【Python修仙笔记.3】Python函数作为秘技 - 封装你的仙法
后端·python