大家好,我是 SiKi老师。给游戏项目写一个小工具,明明配置就在脚本旁边,从另一个目录启动却读不到,这是为什么?相对路径的起点通常是进程当前工作目录,而不是脚本所在目录。先把两者打印出来,再决定配置应该从哪里找,比不断移动文件更容易定位问题。
下面是一个独立的本地文件实验。2026 年 10 月 5 日已在 Windows、Python 3.12.14 中运行验证,不使用第三方包,不读取真实项目、账号或私人配置。这里讨论普通.py文件通过命令行启动的情况,不保证打包程序、Notebook 或引擎内嵌 Python 环境有相同资源布局。
一 用一个最小目录复现
在新建练习目录中建立下面的结构,避免覆盖已有项目。settings.txt只放一行volume=10,以 UTF-8 保存。这个字段只用于观察文件内容,不代表游戏引擎接受这种配置。
练习目录/ path-demo/ check_paths.py data/ settings.txt脚本如下。它只检查和读取练习文件,不创建目录,不改动配置,不切换整个进程的工作目录。
frompathlibimportPath relative=Path("data/settings.txt")beside_script=Path(__file__).resolve().parent/"data"/"settings.txt"print("cwd:",Path.cwd().name)print("relative exists:",relative.is_file())print("beside script exists:",beside_script.is_file())print("content:",beside_script.read_text(encoding="utf-8").strip())Path.cwd()用来取得当前目录,resolve()将路径解析为绝对路径;本文只在普通本地目录验证,没有加入符号链接场景。相关接口定义见 Python 3.12 pathlib 文档。
二 从脚本目录启动一次
先让终端位于path-demo,运行python check_paths.py。这里的 python 应当指向你准备使用的解释器;如果电脑没有这个命令,先核对环境,不要把解释器启动失败当成路径错误。
本次实验输出如下:
cwd: path-demo relative exists: True beside script exists: True content: volume=10此时工作目录恰好就是脚本目录,两种拼法都指向那份练习配置。这种成功容易让人误以为相对路径始终从脚本旁边开始,但单次运行还没有区分两种起点。
三 回到上一级再启动同一个脚本
保持所有文件不动,让终端位于练习目录,运行python path-demo/check_paths.py。本次验证中,第一种检查变为 False,第二种仍为 True,最后仍读到了volume=10。
第一行的目录名会是你自己的练习目录名称,因此不必与别人的电脑逐字相同。关键观察是:启动位置改变后,data/settings.txt会在当前目录下寻找,而脚本旁边的那份文件仍位于path-demo/data。
| 启动所在位置 | 相对路径检查 | 脚本目录拼接检查 |
|---|---|---|
path-demo | True | True |
| 它的上一级练习目录 | False | True |
表格是本次具体目录结构的实测结果,不是所有机器的固定答案。如果你在上一级也建了data/settings.txt,第一种检查可能同样为 True,甚至读到另一份文件。因此“能读到”还不够,还要确认读的是哪一份。
四 根据配置约定选择起点
若资源约定随脚本放置,脚本目录可以作为一个候选起点。若工具本来就要求用户从待处理项目目录启动,那么当前工作目录可能正是需要的入口。这两种设计都可以成立,不能把所有相对路径一律改成脚本目录。
我会先在工具说明中写清楚:“这份文件由工具提供,还是由用户选择?”前者可能跟程序一起分发,后者通常需要明确输入位置。本文不提供打包资源或用户目录的完整方案,也不把源代码旁边的目录当成通用可写目录。
排查时可以临时打印完整解析路径,但截图对外分享前应遮去私人目录和项目名称。不要为了展示路径,把真实配置内容、令牌或账号信息一起打印出来;本文的读取示例只适用于自建的非敏感练习文件。
五 区分路径选择与读取失败
选对文件位置并不保证读取总成功。文件可能缺失、没有权限,或实际编码不是 UTF-8。本例故意不吞掉异常:若最后一步失败,保留错误类型和目标位置,先核对具体原因,别把任意失败都转成一份看似正常的默认配置。
is_file()的观察也不应当作随后读取必然成功的保证,文件状态可能在两步之间变化。生产工具应按自己的失败处理需求捕获相应异常,并给用户清楚提示;这篇只演示如何辨认路径起点,不是完整配置加载器。
你的小工具希望读取“随脚本提供的配置”,还是“当前项目中的配置”?先确定这个约定,再选择起点,才能解释为什么换一种启动方式会出现不同结果。