好的,现在开始讲解 Python 文件 I/O:os
和 pathlib
的高级用法。
Python 文件 I/O:os
和 pathlib
的高级用法
文件 I/O (Input/Output) 是任何编程语言的基础操作之一。Python 提供了多种方法来处理文件,其中 os
和 pathlib
模块是最常用的两个。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. os
和 pathlib
的选择
os
和 pathlib
模块都提供了文件 I/O 功能,选择哪个模块取决于具体的需求和个人偏好。
-
os
模块:- 优点:功能强大,与操作系统紧密集成,提供了许多底层操作。
- 缺点:使用起来比较繁琐,代码可读性较差。
- 适用场景:需要执行底层操作系统操作,例如进程管理、环境变量等。
-
pathlib
模块:- 优点:面向对象,使用起来更简洁、更直观,代码可读性更好。
- 缺点:功能相对较少,不如
os
模块强大。 - 适用场景:主要用于文件和目录的路径操作,以及简单的文件 I/O 操作。
表格对比:os
vs pathlib
特性 | os 模块 |
pathlib 模块 |
---|---|---|
编程风格 | 面向过程 | 面向对象 |
代码可读性 | 较低 | 较高 |
功能 | 强大,底层操作 | 相对较少,主要用于路径操作 |
操作系统集成 | 紧密集成 | 抽象层,平台无关 |
易用性 | 较复杂 | 较简单 |
适用场景 | 底层操作系统操作,进程管理,环境变量等 | 文件和目录路径操作,简单的文件 I/O 操作 |
4. 高级技巧和注意事项
-
使用
try...except
块处理异常: 文件 I/O 操作可能会引发各种异常,例如FileNotFoundError
、PermissionError
等。使用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 代码。掌握这些高级用法,能够让你更有效地处理文件相关的任务。