HOWTO · Python
如何在 Python 中打开其他目录中的文件
了解如何使用绝对路径、pathlib 或相对路径打开当前工作目录之外的文件,并掌握 Python 如何解析路径。
本页内容
将文件路径传给 Python 的 open() 函数即可打开文件。绝对路径从文件系统根目录开始标识文件;相对路径则以进程的当前工作目录(CWD)为起点。CWD 可能与脚本所在目录不同。对于项目中的文件,使用 pathlib.Path 可以方便地构造适用于不同操作系统的路径。
理解文件路径和当前工作目录
CWD 是 Python 解析相对路径时使用的目录。它通常是启动程序时所在的目录,而不是脚本所在目录。如果路径指向的位置与预期不符,可以先查看 CWD:
import os
print(os.getcwd())
绝对路径不受 CWD 影响,直接指向某个位置。像 data/notes.txt 这样的相对路径,会被解释为 CWD 下的路径。如果 open() 找不到解析后的文件位置,Python 会引发 FileNotFoundError;修改代码前,先检查路径本身和 CWD。
使用绝对路径打开文件
如果知道文件所在位置,可以使用完整路径。下面的示例会在一个绝对临时路径下创建文件、读取文件内容并将其打印出来:
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
file_path = Path(directory) / "notes.txt"
file_path.write_text("Meeting at 10", encoding="utf-8")
with open(file_path, "r", encoding="utf-8") as file:
print(file.read())
临时目录让示例不依赖你电脑上已有的文件。在实际程序中,将它替换为文件的真实位置。"r" 模式用于读取文本,encoding="utf-8" 则明确指定文本编码。with 语句会在代码块结束时关闭文件,即使块内发生错误也一样。
在 Windows 上,可以使用正斜杠书写路径,也可以使用原始字符串,例如 r"C:\Users\Ada\notes.txt",或将反斜杠转义,例如 "C:\\Users\\Ada\\notes.txt"。只有反斜杠后面跟着有效的转义序列时,它才表示转义;例如,\n 表示换行符。原始字符串字面量不能以单个反斜杠结尾。使用 pathlib 从路径片段构造路径,可以避免大部分字符串转义处理。
使用 pathlib 构造路径
pathlib.Path 是用于表示和组合文件系统路径的类。/ 运算符会按照当前操作系统的路径规则连接各个部分。下面的示例会在同级目录中创建文件,并通过它的绝对路径打开文件:
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as parent:
root = Path(parent)
current = root / "app"
other = root / "shared"
current.mkdir()
other.mkdir()
target = other / "notes.txt"
target.write_text("Shared notes", encoding="utf-8")
file_path = target.resolve()
with open(file_path, "r", encoding="utf-8") as file:
print(file.read())
在实际项目中,可以从已知目录开始,像这样逐层添加子目录和文件名:Path("/srv/project") / "data" / "notes.txt"。如果程序无论从哪里启动都必须找到该文件,请从绝对路径开始。对于已存在的目标,Path.resolve() 会返回其绝对路径,也能让路径问题更容易诊断。
使用相对路径或更改工作目录
假设项目中有 scripts/read_notes.py 和 shared/notes.txt,且 CWD 是 project/scripts。从这个 CWD 出发,../shared/notes.txt 会先返回上一级到 project,再进入 shared。如果启动目录固定,这种写法很方便;但程序从不同 CWD 启动时,同一个相对路径可能指向别处。若要以脚本所在目录为基准构造项目路径,可以从 Path(__file__).resolve().parent 开始。
下面这个可运行示例会创建项目目录结构,将进程的 CWD 设为 project/scripts,然后使用上下文管理器读取同级目录中的文件:
import os
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
project = Path(directory) / "project"
scripts = project / "scripts"
shared = project / "shared"
scripts.mkdir(parents=True)
shared.mkdir()
(shared / "notes.txt").write_text("Project notes", encoding="utf-8")
original_directory = os.getcwd()
try:
os.chdir(scripts)
with open("../shared/notes.txt", "r", encoding="utf-8") as file:
print(file.read())
finally:
os.chdir(original_directory)
相对路径是根据进程的 CWD 解析的;本例将其设为 project/scripts。路径不会根据源文件所在目录解析。
如果程序需要处理同一目录中的多个文件,可以更改进程的 CWD,然后使用较短的相对路径。下面的示例会在切换目录前创建输入文件,并在之后恢复原来的 CWD:
import os
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
target = Path(directory) / "notes.txt"
target.write_text("Daily notes", encoding="utf-8")
original_directory = os.getcwd()
try:
os.chdir(directory)
with open("notes.txt", "r", encoding="utf-8") as file:
print(file.read())
finally:
os.chdir(original_directory)
os.chdir() 会改变整个进程的状态,因此程序其他部分的相对路径解析也会随之改变。恢复之前的目录可以限制这种影响。只打开一个文件时,直接传入绝对路径或 pathlib 路径通常更简单。如果仍无法读取文件,除了确认文件位置,也要检查当前进程是否有读取权限。