`Python`的`文件`I/O:`os`和`pathlib`的`高级`用法。

好的,现在开始讲解 Python 文件 I/O:ospathlib 的高级用法。

Python 文件 I/O:ospathlib 的高级用法

文件 I/O (Input/Output) 是任何编程语言的基础操作之一。Python 提供了多种方法来处理文件,其中 ospathlib 模块是最常用的两个。os 模块提供了与操作系统交互的功能,包括文件和目录操作,而 pathlib 模块则提供了一种面向对象的方式来操作文件路径。本讲座将深入探讨这两个模块的高级用法,帮助你更有效地进行文件 I/O 操作。

1. os 模块高级用法

os 模块提供了一系列函数,用于执行与操作系统相关的任务,如创建、删除、重命名文件和目录,以及获取文件信息等。

1.1. 文件和目录操作

  • 创建目录:

    os.mkdir(path, mode=0o777):创建单个目录。

    os.makedirs(path, mode=0o777, exist_ok=False):递归创建目录,如果父目录不存在,则自动创建。exist_ok=True 表示如果目录已存在,则不引发异常。

    import os
    
    try:
        os.makedirs("path/to/new/directory", exist_ok=True)
        print("目录创建成功")
    except OSError as e:
        print(f"创建目录失败: {e}")
  • 删除文件和目录:

    os.remove(path)os.unlink(path):删除文件。

    os.rmdir(path):删除空目录。

    os.removedirs(path):递归删除目录,直到遇到非空目录为止。

    shutil.rmtree(path, ignore_errors=False, onerror=None):删除目录及其所有内容,即使目录非空。需要导入 shutil 模块。

    import os
    import shutil
    
    try:
        os.remove("file.txt")
        os.rmdir("empty_directory")
        shutil.rmtree("non_empty_directory")
        print("文件和目录删除成功")
    except OSError as e:
        print(f"删除文件和目录失败: {e}")
  • 重命名文件和目录:

    os.rename(src, dst):重命名文件或目录。

    os.renames(old, new):递归重命名目录,如果目标目录的父目录不存在,则自动创建。

    import os
    
    try:
        os.rename("old_name.txt", "new_name.txt")
        os.renames("old_directory", "new_directory")
        print("文件和目录重命名成功")
    except OSError as e:
        print(f"重命名文件和目录失败: {e}")
  • 检查文件和目录是否存在:

    os.path.exists(path):检查路径是否存在。

    os.path.isfile(path):检查路径是否为文件。

    os.path.isdir(path):检查路径是否为目录。

    import os
    
    if os.path.exists("file.txt"):
        print("文件存在")
    if os.path.isfile("file.txt"):
        print("是文件")
    if os.path.isdir("directory"):
        print("是目录")

1.2. 文件属性和权限

  • 获取文件大小:

    os.path.getsize(path):返回文件的大小,以字节为单位。

    import os
    
    file_size = os.path.getsize("file.txt")
    print(f"文件大小: {file_size} 字节")
  • 获取文件修改时间:

    os.path.getmtime(path):返回文件最后修改的时间戳(从 epoch 开始的秒数)。

    import os
    import time
    
    modification_time = os.path.getmtime("file.txt")
    readable_time = time.ctime(modification_time)
    print(f"最后修改时间: {readable_time}")
  • 修改文件权限:

    os.chmod(path, mode):修改文件的权限。mode 是一个整数,表示权限模式。可以使用 stat 模块中的常量,如 stat.S_IRUSR (用户读权限), stat.S_IWUSR (用户写权限), stat.S_IXUSR (用户执行权限) 等。

    import os
    import stat
    
    try:
        os.chmod("file.txt", stat.S_IRUSR | stat.S_IWUSR) # 用户读写权限
        print("权限修改成功")
    except OSError as e:
        print(f"权限修改失败: {e}")

1.3. 目录遍历

  • os.listdir(path) 返回指定目录中所有文件和目录的名称列表。

    import os
    
    directory_contents = os.listdir(".")  # 当前目录
    print(directory_contents)
  • os.scandir(path) 返回一个 os.DirEntry 对象的迭代器,每个对象包含文件或目录的信息,例如名称、路径、是否为文件或目录等。 比 os.listdir 更高效,特别是对于大型目录。

    import os
    
    for entry in os.scandir("."):
        print(f"名称: {entry.name}, 路径: {entry.path}, 是否为文件: {entry.is_file()}, 是否为目录: {entry.is_dir()}")
  • os.walk(top, topdown=True, onerror=None, followlinks=False) 递归地遍历目录树,返回一个三元组 (dirpath, dirnames, filenames) 的生成器。dirpath 是当前目录的路径,dirnames 是当前目录中所有子目录的名称列表,filenames 是当前目录中所有文件的名称列表。

    • topdown=True:先遍历顶层目录,再遍历子目录(默认)。
    • topdown=False:先遍历子目录,再遍历顶层目录。
    • onerror=None:如果发生错误,则调用该函数。
    • followlinks=False:是否跟随符号链接。
    import os
    
    for dirpath, dirnames, filenames in os.walk("."):
        print(f"目录: {dirpath}")
        print(f"子目录: {dirnames}")
        print(f"文件: {filenames}")
        print("-" * 20)

1.4. 环境变量

  • os.environ 一个字典,包含系统的环境变量。

    import os
    
    print(os.environ["PATH"])  # 获取 PATH 环境变量
    os.environ["MY_VAR"] = "my_value"  # 设置环境变量 (仅在当前进程中有效)
    print(os.environ["MY_VAR"])
  • os.getenv(varname, value=None) 获取指定环境变量的值。如果环境变量不存在,则返回 value (默认为 None)。

    import os
    
    home_dir = os.getenv("HOME")
    print(f"Home 目录: {home_dir}")

1.5. 进程管理

  • os.system(command) 在子 shell 中执行命令。返回命令的退出状态码。

    import os
    
    os.system("ls -l")  # 在 Linux/macOS 上列出当前目录的内容
  • *`os.spawn()` 函数族:** 更底层的进程创建函数,允许更精细的控制,但使用起来更复杂。

  • *os.fork() 和 `os.exec()` 函数族:** 用于创建和执行新的进程 (仅在 Unix-like 系统上可用)。

2. pathlib 模块高级用法

pathlib 模块提供了一种面向对象的方式来操作文件路径。它使用 Path 对象来表示文件和目录路径,并提供了许多方法来执行常见的文件 I/O 操作。

2.1. 创建 Path 对象

from pathlib import Path

# 从字符串创建
path = Path("my_file.txt")
print(path)

# 从多个部分创建
path = Path("/home", "user", "documents", "my_file.txt")
print(path)

# 获取当前工作目录的 Path 对象
current_directory = Path.cwd()
print(current_directory)

# 获取用户 Home 目录的 Path 对象
home_directory = Path.home()
print(home_directory)

2.2. 路径操作

  • 连接路径:

    使用 / 运算符连接路径。

    from pathlib import Path
    
    parent_path = Path("/home/user")
    file_path = parent_path / "documents" / "my_file.txt"
    print(file_path)
  • 获取父目录:

    使用 parent 属性获取父目录的 Path 对象。

    from pathlib import Path
    
    file_path = Path("/home/user/documents/my_file.txt")
    parent_path = file_path.parent
    print(parent_path)
  • 获取文件名:

    name 属性:获取不包含路径的文件名。

    stem 属性:获取不包含后缀的文件名。

    suffix 属性:获取文件后缀。

    suffixes 属性:获取所有后缀的列表。

    from pathlib import Path
    
    file_path = Path("/home/user/documents/my_file.tar.gz")
    print(f"文件名: {file_path.name}")
    print(f"文件名 (不含后缀): {file_path.stem}")
    print(f"后缀: {file_path.suffix}")
    print(f"所有后缀: {file_path.suffixes}")
  • 判断路径类型:

    is_file():判断是否为文件。

    is_dir():判断是否为目录。

    is_symlink():判断是否为符号链接。

    exists():判断路径是否存在。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    if file_path.is_file():
        print("是文件")
    if file_path.exists():
        print("路径存在")
  • 解析路径:

    resolve(strict=False):返回绝对路径,解析所有符号链接。strict=True 表示如果路径不存在,则引发 FileNotFoundError 异常。

    absolute():返回绝对路径,但不解析符号链接。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    absolute_path = file_path.resolve()
    print(f"绝对路径: {absolute_path}")

2.3. 文件 I/O 操作

  • 读取文件内容:

    read_text(encoding=None, errors=None):以文本模式读取文件内容,返回字符串。

    read_bytes():以二进制模式读取文件内容,返回字节串。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    try:
        content = file_path.read_text(encoding="utf-8")
        print(content)
    except FileNotFoundError:
        print("文件不存在")
  • 写入文件内容:

    write_text(data, encoding=None, errors=None):以文本模式写入文件内容。

    write_bytes(data):以二进制模式写入文件内容。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    file_path.write_text("Hello, world!", encoding="utf-8")
  • 追加文件内容:

    使用 open() 函数以追加模式打开文件,然后写入内容。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    with file_path.open("a", encoding="utf-8") as f:
        f.write("Append some text.n")

2.4. 目录操作

  • 创建目录:

    mkdir(mode=0o777, parents=False, exist_ok=False):创建目录。parents=True 表示递归创建目录,exist_ok=True 表示如果目录已存在,则不引发异常。

    from pathlib import Path
    
    dir_path = Path("new_directory")
    try:
        dir_path.mkdir(parents=True, exist_ok=True)
        print("目录创建成功")
    except FileExistsError:
        print("目录已存在")
  • 删除文件和目录:

    unlink(missing_ok=False):删除文件或符号链接。 如果文件不存在,且 missing_ok=False,则引发 FileNotFoundError

    rmdir():删除空目录。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    try:
        file_path.unlink()
        print("文件删除成功")
    except FileNotFoundError:
        print("文件不存在")
    
    dir_path = Path("empty_directory")
    try:
        dir_path.rmdir()
        print("目录删除成功")
    except OSError as e:
        print(f"删除目录失败: {e}")
  • 重命名文件和目录:

    rename(target):重命名文件或目录。

    from pathlib import Path
    
    old_path = Path("old_name.txt")
    new_path = Path("new_name.txt")
    try:
        old_path.rename(new_path)
        print("文件重命名成功")
    except FileNotFoundError:
        print("文件不存在")
  • 遍历目录:

    iterdir():返回一个迭代器,包含目录中的所有文件和目录的 Path 对象。

    glob(pattern):返回一个迭代器,包含所有匹配指定模式的文件和目录的 Path 对象。

    rglob(pattern):递归地返回一个迭代器,包含所有匹配指定模式的文件和目录的 Path 对象。

    from pathlib import Path
    
    dir_path = Path(".")
    
    print("iterdir:")
    for item in dir_path.iterdir():
        print(item)
    
    print("nglob:")
    for item in dir_path.glob("*.txt"):
        print(item)
    
    print("nrglob:")
    for item in dir_path.rglob("*.py"):
        print(item)

2.5. 文件属性

  • stat() 方法: 返回一个 stat 对象,包含文件的各种属性,如大小、修改时间、权限等。

    from pathlib import Path
    import time
    
    file_path = Path("my_file.txt")
    stat_info = file_path.stat()
    print(f"文件大小: {stat_info.st_size} 字节")
    print(f"最后修改时间: {time.ctime(stat_info.st_mtime)}")
  • owner()group() 方法: 返回文件所有者和所属组的名称 (仅在 Unix-like 系统上可用)。

    from pathlib import Path
    
    file_path = Path("my_file.txt")
    try:
        owner = file_path.owner()
        group = file_path.group()
        print(f"所有者: {owner}")
        print(f"所属组: {group}")
    except AttributeError:
        print("不支持 owner() 和 group() 方法")

3. ospathlib 的选择

ospathlib 模块都提供了文件 I/O 功能,选择哪个模块取决于具体的需求和个人偏好。

  • os 模块:

    • 优点:功能强大,与操作系统紧密集成,提供了许多底层操作。
    • 缺点:使用起来比较繁琐,代码可读性较差。
    • 适用场景:需要执行底层操作系统操作,例如进程管理、环境变量等。
  • pathlib 模块:

    • 优点:面向对象,使用起来更简洁、更直观,代码可读性更好。
    • 缺点:功能相对较少,不如 os 模块强大。
    • 适用场景:主要用于文件和目录的路径操作,以及简单的文件 I/O 操作。

表格对比:os vs pathlib

特性 os 模块 pathlib 模块
编程风格 面向过程 面向对象
代码可读性 较低 较高
功能 强大,底层操作 相对较少,主要用于路径操作
操作系统集成 紧密集成 抽象层,平台无关
易用性 较复杂 较简单
适用场景 底层操作系统操作,进程管理,环境变量等 文件和目录路径操作,简单的文件 I/O 操作

4. 高级技巧和注意事项

  • 使用 try...except 块处理异常: 文件 I/O 操作可能会引发各种异常,例如 FileNotFoundErrorPermissionError 等。使用 try...except 块可以捕获这些异常,并进行相应的处理,保证程序的健壮性。

  • 使用 with 语句自动关闭文件: with 语句可以确保文件在使用完毕后自动关闭,即使发生异常也是如此。这可以避免文件资源泄漏。

  • 选择合适的编码方式: 在读写文本文件时,需要指定正确的编码方式,以避免出现乱码问题。常用的编码方式包括 UTF-8、GBK 等。

  • 注意文件权限: 在进行文件 I/O 操作时,需要确保具有足够的文件权限。

  • 避免硬编码路径: 尽量使用相对路径或环境变量,而不是硬编码绝对路径,以提高程序的可移植性。

  • 使用 os.path.join()Path 对象的 / 运算符来连接路径: 这样可以确保路径在不同操作系统上的正确性。

  • 考虑性能: 对于大型文件,使用 os.scandir() 代替 os.listdir() 可以提高遍历目录的效率。使用 shutil.copyfile()shutil.copy2() 代替手动读取和写入文件内容可以提高文件复制的效率。

关于文件I/O的总结

os 模块提供操作系统级别的文件操作,功能强大但略显繁琐;pathlib 模块以面向对象的方式处理文件路径,更加简洁易用。根据具体需求选择合适的模块,并注意异常处理、编码方式和文件权限等细节,可以编写出高效、健壮的文件 I/O 代码。掌握这些高级用法,能够让你更有效地处理文件相关的任务。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注