`Python`的`文件`操作:`os`、`pathlib`和`shutil`的`高级`用法。

好的,我们开始。

Python 文件操作:ospathlibshutil 的高级用法

大家好!今天我们深入探讨 Python 中文件操作的三大模块:ospathlibshutil。我们将从基本概念出发,逐步介绍它们的高级用法,并通过实际代码示例来演示如何高效地处理文件和目录。

1. os 模块:系统级别的操作

os 模块提供了与操作系统交互的接口。它允许你执行诸如创建、删除、重命名文件和目录,以及获取文件信息等操作。虽然 pathlib 提供了更面向对象的路径处理方式,但在某些底层操作上,os 模块仍然是不可或缺的。

1.1 目录操作

  • 创建目录:os.mkdir()os.makedirs()

    os.mkdir() 创建一个目录,但如果父目录不存在,则会抛出 FileNotFoundError 异常。os.makedirs() 可以递归地创建目录,即使父目录不存在。

    import os
    
    # 创建单个目录
    try:
        os.mkdir("my_directory")
    except FileExistsError:
        print("目录已存在")
    
    # 递归创建目录
    os.makedirs("parent_directory/child_directory", exist_ok=True) # exist_ok=True 不抛出异常
  • 删除目录:os.rmdir()shutil.rmtree()

    os.rmdir() 删除一个空目录。如果目录不为空,则会抛出 OSError 异常。shutil.rmtree() 可以递归地删除整个目录树,包括所有文件和子目录。

    import os
    import shutil
    
    # 删除空目录
    try:
        os.rmdir("my_directory")
    except OSError:
        print("目录非空或不存在")
    
    # 递归删除目录树
    shutil.rmtree("parent_directory", ignore_errors=True) # 忽略错误
  • 更改当前工作目录:os.chdir()

    os.chdir() 允许你更改 Python 程序的当前工作目录。

    import os
    
    print(f"当前工作目录:{os.getcwd()}")
    os.chdir("parent_directory")
    print(f"当前工作目录:{os.getcwd()}")
    os.chdir("..") # 返回上一级目录
    print(f"当前工作目录:{os.getcwd()}")
    
  • 列出目录内容:os.listdir()os.scandir()

    os.listdir() 返回一个包含目录中所有文件和子目录名称的列表。os.scandir() 返回一个迭代器,产生 os.DirEntry 对象,这些对象包含有关每个文件或目录的更多信息,例如文件类型和大小。os.scandir() 通常比 os.listdir() 更快,尤其是在处理大型目录时。

    import os
    
    # 使用 os.listdir()
    files = os.listdir(".")
    print(f"文件列表 (listdir): {files}")
    
    # 使用 os.scandir()
    with os.scandir(".") as entries:
        for entry in entries:
            print(f"文件名: {entry.name}, 是否是目录: {entry.is_dir()}, 文件大小: {entry.stat().st_size} bytes")

1.2 文件操作

  • 重命名文件:os.rename()os.renames()

    os.rename() 重命名文件或目录。os.renames() 可以递归地创建中间目录,如果需要的话。

    import os
    
    # 重命名文件
    try:
        with open("old_file.txt", "w") as f:
            f.write("This is a test file.")
        os.rename("old_file.txt", "new_file.txt")
    except FileNotFoundError:
        print("文件不存在")
    
    # 递归重命名
    try:
        os.renames("a/b/old_file.txt", "a/c/new_file.txt") # 如果 a/c 不存在,则会创建
    except FileNotFoundError:
        print("文件不存在")
  • 删除文件:os.remove()

    os.remove() 删除指定的文件。

    import os
    
    # 删除文件
    try:
        os.remove("new_file.txt")
    except FileNotFoundError:
        print("文件不存在")
  • 获取文件信息:os.stat()

    os.stat() 返回一个包含文件信息的对象,例如大小、修改时间、权限等。

    import os
    import time
    
    # 创建一个示例文件
    with open("example.txt", "w") as f:
        f.write("This is a test file.")
    
    # 获取文件状态信息
    stat_info = os.stat("example.txt")
    print(f"文件大小:{stat_info.st_size} 字节")
    print(f"最后修改时间:{time.ctime(stat_info.st_mtime)}")
    print(f"权限:{stat_info.st_mode}")
    
    # 删除示例文件
    os.remove("example.txt")

1.3 环境变量

os模块可以访问和修改环境变量。

  • os.environ:一个字典,包含当前的环境变量。
  • os.getenv(varname, value=None):获取环境变量的值。如果变量不存在,返回value,如果value未指定,则返回None
  • os.putenv(varname, value):设置环境变量的值。注意:这个函数可能会影响到其他进程。不推荐使用,推荐使用os.environ直接修改字典。
import os

# 获取环境变量
home_dir = os.getenv("HOME")
print(f"Home 目录:{home_dir}")

# 设置环境变量 (不推荐)
# os.putenv("MY_VAR", "my_value") # 可能会影响其他进程

# 使用 os.environ 设置环境变量 (推荐)
os.environ["MY_VAR"] = "my_value"
print(f"MY_VAR: {os.environ['MY_VAR']}")

# 删除环境变量
del os.environ["MY_VAR"]
# print(f"MY_VAR: {os.environ['MY_VAR']}") # KeyError: 'MY_VAR'

1.4 进程管理

os模块提供了一些基本的进程管理功能。

  • os.system(command):在子shell中执行命令。
  • os.fork():创建一个新的进程。(仅在Unix系统上可用)
  • os.execv(path, args):用新的程序替换当前进程。(仅在Unix系统上可用)
import os

# 执行系统命令
os.system("ls -l")

# 仅在Unix系统上可用
# pid = os.fork()
# if pid == 0:
#     # 子进程
#     os.execv("/bin/ls", ["ls", "-l"])
# else:
#     # 父进程
#     print(f"子进程 ID: {pid}")
#     os.wait() # 等待子进程完成

2. pathlib 模块:面向对象的路径操作

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

2.1 创建 Path 对象

from pathlib import Path

# 从字符串创建 Path 对象
path = Path("my_directory/my_file.txt")

# 从多个部分创建 Path 对象
path = Path("my_directory", "my_file.txt")

# 创建一个指向当前工作目录的 Path 对象
current_directory = Path(".")

# 创建一个指向用户主目录的 Path 对象
home_directory = Path.home()

print(f"Path 对象: {path}")
print(f"当前目录: {current_directory}")
print(f"Home 目录: {home_directory}")

2.2 路径操作

  • 连接路径:/ 运算符

    可以使用 / 运算符来连接路径。

    from pathlib import Path
    
    parent_directory = Path("parent_directory")
    child_directory = Path("child_directory")
    file_path = parent_directory / child_directory / "my_file.txt"
    
    print(f"文件路径:{file_path}")
  • 获取路径信息

    from pathlib import Path
    
    path = Path("parent_directory/child_directory/my_file.txt")
    
    print(f"父目录:{path.parent}")
    print(f"文件名:{path.name}")
    print(f"不带后缀的文件名:{path.stem}")
    print(f"文件后缀:{path.suffix}")
    print(f"绝对路径:{path.resolve()}")
  • 检查路径是否存在:exists()

    from pathlib import Path
    
    path = Path("parent_directory/child_directory/my_file.txt")
    
    if path.exists():
        print("路径存在")
    else:
        print("路径不存在")
  • 检查路径类型:is_file()is_dir()

    from pathlib import Path
    
    path = Path("parent_directory/child_directory/my_file.txt")
    
    if path.is_file():
        print("是文件")
    elif path.is_dir():
        print("是目录")
    else:
        print("既不是文件也不是目录")
  • 创建目录:mkdir()

    from pathlib import Path
    
    path = Path("new_directory")
    path.mkdir(parents=True, exist_ok=True) # parents=True 递归创建,exist_ok=True 不抛出异常
  • 删除文件或目录:unlink()rmdir()

    from pathlib import Path
    
    # 删除文件
    file_path = Path("my_file.txt")
    file_path.unlink(missing_ok=True) # missing_ok=True 不抛出异常
    
    # 删除目录 (必须为空)
    dir_path = Path("empty_directory")
    dir_path.rmdir()
  • 遍历目录:iterdir()glob()

    iterdir() 返回一个迭代器,产生目录中的所有文件和子目录的 Path 对象。glob() 允许你使用通配符来查找匹配特定模式的文件。

    from pathlib import Path
    
    # 创建一些示例文件和目录
    Path("directory_1").mkdir(exist_ok=True)
    Path("directory_2").mkdir(exist_ok=True)
    Path("file_1.txt").touch()
    Path("file_2.txt").touch()
    Path("directory_1/file_3.txt").touch()
    
    # 使用 iterdir()
    directory = Path(".")
    for item in directory.iterdir():
        print(item)
    
    # 使用 glob()
    for item in directory.glob("*.txt"):
        print(item)
    
    for item in directory.glob("**/*.txt"): # 递归查找
        print(item)
    
    # 清理示例文件和目录
    import shutil
    shutil.rmtree("directory_1", ignore_errors=True)
    shutil.rmtree("directory_2", ignore_errors=True)
    Path("file_1.txt").unlink(missing_ok=True)
    Path("file_2.txt").unlink(missing_ok=True)
    

2.3 文件读写

pathlib 提供了方便的方法来读取和写入文件。

  • 读取文件:read_text()read_bytes()

    from pathlib import Path
    
    # 创建一个示例文件
    file_path = Path("my_file.txt")
    file_path.write_text("Hello, world!")
    
    # 读取文本文件
    content = file_path.read_text()
    print(f"文件内容:{content}")
    
    # 读取二进制文件
    binary_content = file_path.read_bytes()
    print(f"文件内容(二进制):{binary_content}")
    
    # 删除示例文件
    file_path.unlink()
  • 写入文件:write_text()write_bytes()

    from pathlib import Path
    
    # 创建一个 Path 对象
    file_path = Path("my_file.txt")
    
    # 写入文本文件
    file_path.write_text("Hello, world!")
    
    # 写入二进制文件
    file_path.write_bytes(b"Hello, world!")
    
    # 删除示例文件
    file_path.unlink()

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

shutil 模块提供了许多高级的文件操作,例如复制、移动、重命名和删除文件和目录树。它通常用于执行更复杂的文件管理任务。

3.1 文件复制

  • shutil.copy(src, dst):复制文件 srcdst。目标可以是文件或目录。如果 dst 是目录,则文件将复制到该目录中,并保留原始文件名。只复制文件内容和权限。
  • shutil.copy2(src, dst):与 copy() 类似,但还会复制文件的元数据,例如最后访问时间和修改时间。
  • shutil.copytree(src, dst):递归地复制整个目录树。
import shutil
from pathlib import Path

# 创建一些示例文件和目录
Path("source_directory").mkdir(exist_ok=True)
Path("source_directory/file_1.txt").touch()
Path("source_file.txt").touch()

# 复制文件
shutil.copy("source_file.txt", "destination_file.txt")
shutil.copy2("source_file.txt", "destination_file_2.txt") # 复制元数据
shutil.copy("source_file.txt", "source_directory") # 复制到目录

# 复制目录树
shutil.copytree("source_directory", "destination_directory")

# 清理示例文件和目录
Path("destination_file.txt").unlink()
Path("destination_file_2.txt").unlink()
shutil.rmtree("source_directory", ignore_errors=True)
shutil.rmtree("destination_directory", ignore_errors=True)
Path("source_file.txt").unlink()

3.2 文件移动和重命名

  • shutil.move(src, dst):移动文件或目录 srcdst。如果 dst 已经存在,并且是目录,则 src 将移动到该目录中。如果 dst 存在且是文件,则会被覆盖。
import shutil
from pathlib import Path

# 创建一些示例文件和目录
Path("source_file.txt").touch()
Path("source_directory").mkdir(exist_ok=True)

# 移动文件
shutil.move("source_file.txt", "destination_file.txt") # 重命名
shutil.move("destination_file.txt", "source_directory") # 移动到目录

# 清理示例文件和目录
shutil.rmtree("source_directory", ignore_errors=True)

3.3 文件和目录删除

  • shutil.rmtree(path, ignore_errors=False, onerror=None):递归地删除整个目录树。如果 ignore_errorsTrue,则忽略删除错误。如果 onerror 提供,它应该是一个可调用对象,接受三个参数:function, path, and excinfo
import shutil
from pathlib import Path

# 创建一个示例目录树
Path("my_directory/child_directory").mkdir(parents=True, exist_ok=True)
Path("my_directory/file_1.txt").touch()
Path("my_directory/child_directory/file_2.txt").touch()

# 递归删除目录树
shutil.rmtree("my_directory", ignore_errors=True)

3.4 归档操作

shutil 模块还提供了一些归档操作,例如创建和提取 ZIP 文件和 tar 文件。

  • shutil.make_archive(base_name, format, root_dir=None, base_dir=None):创建一个归档文件。
  • shutil.unpack_archive(filename, extract_dir=None, format=None):提取归档文件。
import shutil
from pathlib import Path

# 创建一些示例文件和目录
Path("my_directory/child_directory").mkdir(parents=True, exist_ok=True)
Path("my_directory/file_1.txt").touch()
Path("my_directory/child_directory/file_2.txt").touch()

# 创建 ZIP 归档
shutil.make_archive("my_archive", "zip", root_dir=".") # 将当前目录下的所有内容归档

# 提取 ZIP 归档
shutil.unpack_archive("my_archive.zip", extract_dir="extracted_directory")

# 清理示例文件和目录
shutil.rmtree("my_directory", ignore_errors=True)
shutil.rmtree("extracted_directory", ignore_errors=True)
Path("my_archive.zip").unlink()

3.5 磁盘空间

shutil模块提供获取磁盘空间使用情况的函数。

  • shutil.disk_usage(path):返回一个命名元组,包含总空间、已用空间和可用空间。
import shutil

total, used, free = shutil.disk_usage(".")
print(f"总空间: {total // (2**30)} GB")
print(f"已用空间: {used // (2**30)} GB")
print(f"可用空间: {free // (2**30)} GB")
模块 主要功能 优点 缺点
os 系统级别的文件和目录操作,环境变量,进程管理。 底层操作,功能强大,与操作系统交互紧密。 路径处理比较繁琐,需要手动拼接字符串,错误处理需要更多代码。
pathlib 面向对象的路径操作,文件读写。 面向对象,代码更简洁易读,提供更多方便的方法,更容易处理跨平台路径问题。 某些底层操作不如 os 模块直接。
shutil 高级文件操作,例如复制、移动、重命名、删除、归档。 提供高级功能,简化复杂的文件管理任务,例如递归复制目录树。 功能相对较少,主要集中在文件管理方面。

总结一下三个模块的特点

os 提供底层系统交互,pathlib 提供面向对象的路径处理,shutil 提供高级文件操作功能。三者结合使用,可以高效地完成各种文件管理任务。选择哪个模块取决于具体的任务需求和个人偏好。通常,pathlib 是首选,因为它更易于使用,但在需要底层操作时,os 仍然是必要的。shutil 则用于处理更高级的文件管理任务。

希望今天的讲解对大家有所帮助!

发表回复

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