VS Code 中 Python 相对路径失效?从 `FileNotFoundError` 深入理解当前工作目录问题
目录
- VS Code 中 Python 相对路径失效?从 `FileNotFoundError` 深入理解当前工作目录问题
-
- 1. 问题背景
- 2. 问题的本质:相对路径不是相对于 py 文件,而是相对于“当前工作目录”
- 3. 为什么 PyCharm 里经常没问题,而 VS Code 容易出问题?
- 4. 第一种解决方案:让 VS Code 普通运行时从当前文件目录启动
- 5. 第二种解决方案:Debug 时配置 `launch.json`
- 6. 有了 launch.json 仍然不生效,通常是这几个原因
- 7. 最推荐的工程写法:不要依赖 VS Code 的当前工作目录
- 8. 为什么 `Path(__file__).resolve().parents[2]` 是项目根目录?
- 9. 建议封装一个通用路径工具
- 10. 另一个实用技巧:自动读取最新生成的文件
- 11. 排查路径问题的固定模板
- 12. 最终推荐方案
- 13. 总结
VS Code 中 Python 相对路径失效?从 FileNotFoundError 深入理解当前工作目录问题
1. 问题背景
在 Python 数据分析项目中,我们经常会把代码文件和数据文件分开放置,例如:
sample_turbine_mast_analysis
├─ output
│ └─ all_files_resampled_20260611_162930.csv
│
└─ veer_power_analysis
└─ 01_preprocessing
└─ m1_nacelle_wind_bias.py
当前运行的 Python 文件是:
sample_turbine_mast_analysis/veer_power_analysis/01_preprocessing/m1_nacelle_wind_bias.py
想读取的 CSV 文件是:
sample_turbine_mast_analysis/output/all_files_resampled_20260611_162930.csv
于是很自然地写出下面代码:
import pandas as pd
df = pd.read_csv("../../output/all_files_resampled_20260611_162930.csv")
从目录结构上看,这个路径似乎没问题:
当前 py 文件目录:
sample_turbine_mast_analysis/veer_power_analysis/01_preprocessing
../../output/
等价于:
sample_turbine_mast_analysis/output/
但运行时却报错:
FileNotFoundError: [Errno 2] No such file or directory:
'../../output/all_files_resampled_20260611_162930.csv'
这类问题在 PyCharm 中可能很少遇到,但在 VS Code 中非常常见。
2. 问题的本质:相对路径不是相对于 py 文件,而是相对于“当前工作目录”
很多初学者都会有一个误解:
Python 中的相对路径,是相对于当前正在运行的
.py文件所在目录。
但真实情况通常是:
Python 中的相对路径,是相对于当前工作目录,也就是
os.getcwd()或Path.cwd()所指向的位置。
也就是说,代码中写的:
"../../output/all_files_resampled_20260611_162930.csv"
并不一定是从 m1_nacelle_wind_bias.py 所在目录开始往上找,而是从当前工作目录开始往上找。
可以用下面代码验证:
from pathlib import Path
import sys
print("当前运行的 Python 路径:")
print(sys.executable)
print("当前工作目录:")
print(Path.cwd())
print("当前 py 文件所在目录:")
print(Path(__file__).resolve().parent)
实际输出为:
当前运行的 Python 路径:
C:\Users\54867\.conda\envs\ewm_ti\python.exe
当前工作目录:
F:\09-code\20-LTC
这就说明,VS Code 当前运行时的起点并不是:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis\01_preprocessing
而是:
F:\09-code\20-LTC
因此这行代码:
pd.read_csv("../../output/all_files_resampled_20260611_162930.csv")
实际会被解释成:
F:\09-code\20-LTC\..\..\output\all_files_resampled_20260611_162930.csv
也就是:
F:\output\all_files_resampled_20260611_162930.csv
但真实文件在:
F:\09-code\20-LTC\sample_turbine_mast_analysis\output\all_files_resampled_20260611_162930.csv
所以必然报错。
3. 为什么 PyCharm 里经常没问题,而 VS Code 容易出问题?
因为二者默认的运行习惯不同。
PyCharm 通常会比较明确地设置运行配置,比如:
- 当前脚本路径;
- 当前工作目录;
- Python 解释器;
- 环境变量;
- 参数配置。
很多情况下,PyCharm 的运行目录会更接近当前脚本所在目录,或者至少能在 Run Configuration 里直观看到。
而 VS Code 更灵活,但也更容易“隐式”出问题。它可能把下面这个目录作为当前工作目录:
F:\09-code\20-LTC
也就是 VS Code 当前打开的工作区根目录。
这就会导致一个现象:
同一段相对路径代码,在 PyCharm 能跑,在 VS Code 报
FileNotFoundError。
本质不是 pandas 的问题,也不是文件不存在,而是路径解析起点变了。
4. 第一种解决方案:让 VS Code 普通运行时从当前文件目录启动
如果只是点击 VS Code 右上角的普通运行按钮,例如:
Run Python File
可以设置:
{
"python.terminal.executeInFileDir": true
}
设置方法:
- 打开 VS Code;
- 按
Ctrl + Shift + P; - 输入
Preferences: Open User Settings (JSON); - 加入:
{
"python.terminal.executeInFileDir": true
}
这个配置的作用是:
普通运行 Python 文件时,把当前工作目录切换为当前
.py文件所在目录。
设置之后,运行:
from pathlib import Path
print(Path.cwd())
期望输出应该变成:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis\01_preprocessing
这样:
pd.read_csv("../../output/all_files_resampled_20260611_162930.csv")
就可以正常找到文件。
但是要注意:这个配置主要影响普通运行,不一定影响 Debug。
5. 第二种解决方案:Debug 时配置 launch.json
如果使用的是 Debug,例如:
F5
或者左侧“运行和调试”,那么 VS Code 通常会读取项目下的:
.vscode/launch.json
这时需要显式设置 cwd。
推荐配置如下:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debug 当前文件目录",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${fileDirname}",
"justMyCode": true
}
]
}
其中最关键的是:
"cwd": "${fileDirname}"
意思是:
Debug 时,把当前工作目录设置为当前正在运行的
.py文件所在目录。
如果 VS Code 当前打开的工作区是:
F:\09-code\20-LTC
那么 launch.json 应该放在:
F:\09-code\20-LTC\.vscode\launch.json
而不是放在:
F:\09-code\20-LTC\sample_turbine_mast_analysis\.vscode\launch.json
也不是放在更深层目录。
这是一个非常容易踩坑的点。
6. 有了 launch.json 仍然不生效,通常是这几个原因
6.1 launch.json 放错位置
假设 VS Code 打开的根目录是:
F:\09-code\20-LTC
那么 VS Code 会优先读取:
F:\09-code\20-LTC\.vscode\launch.json
如果你把配置文件放到了:
F:\09-code\20-LTC\sample_turbine_mast_analysis\.vscode\launch.json
但 VS Code 打开的根目录不是 sample_turbine_mast_analysis,那这个配置可能不会被使用。
6.2 Debug 时没有选中对应配置
创建了 launch.json 后,左侧“运行和调试”顶部会出现一个配置下拉框。
需要选择:
Python Debug 当前文件目录
然后再按 F5。
如果仍然使用默认的:
Python Debugger: Current File
那可能不会走你自定义的 cwd 配置。
6.3 点击的是右上角 Debug 按钮
VS Code 右上角的 Debug 按钮有时不走左侧选中的 Debug 配置。
如果想让右上角的 Debug 按钮也使用这个配置,可以尝试增加:
"purpose": ["debug-in-terminal"]
完整示例:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debug 当前文件目录",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${fileDirname}",
"purpose": ["debug-in-terminal"],
"justMyCode": true
}
]
}
不过更稳妥的做法是:
从左侧“运行和调试”中选择自己的配置,然后启动 Debug。
7. 最推荐的工程写法:不要依赖 VS Code 的当前工作目录
虽然可以通过 VS Code 设置解决问题,但从工程稳定性来说,更推荐直接在代码中基于当前 .py 文件定位路径。
也就是不要写:
pd.read_csv("../../output/all_files_resampled_20260611_162930.csv")
而是写:
from pathlib import Path
import pandas as pd
# 当前 py 文件:
# sample_turbine_mast_analysis/veer_power_analysis/01_preprocessing/m1_nacelle_wind_bias.py
current_file = Path(__file__).resolve()
# 项目根目录:
# sample_turbine_mast_analysis
project_root = current_file.parents[2]
# 目标 CSV 文件
csv_path = project_root / "output" / "all_files_resampled_20260611_162930.csv"
print("当前 py 文件:", current_file)
print("项目根目录:", project_root)
print("CSV 路径:", csv_path)
print("文件是否存在:", csv_path.exists())
df = pd.read_csv(csv_path, encoding="utf-8-sig")
这段代码不关心 VS Code 当前工作目录是什么。
无论你在:
- VS Code 普通运行;
- VS Code Debug;
- PyCharm;
- 命令行;
- 定时任务;
- 其他 IDE;
只要这个 .py 文件和 output 文件夹的相对位置不变,它就能稳定找到数据文件。
8. 为什么 Path(__file__).resolve().parents[2] 是项目根目录?
当前文件路径是:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis\01_preprocessing\m1_nacelle_wind_bias.py
那么:
Path(__file__).resolve().parent
得到:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis\01_preprocessing
继续往上:
Path(__file__).resolve().parents[0]
得到:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis\01_preprocessing
Path(__file__).resolve().parents[1]
得到:
F:\09-code\20-LTC\sample_turbine_mast_analysis\veer_power_analysis
Path(__file__).resolve().parents[2]
得到:
F:\09-code\20-LTC\sample_turbine_mast_analysis
而 output 文件夹正好在:
F:\09-code\20-LTC\sample_turbine_mast_analysis\output
所以可以拼接:
csv_path = project_root / "output" / "all_files_resampled_20260611_162930.csv"
最终得到:
F:\09-code\20-LTC\sample_turbine_mast_analysis\output\all_files_resampled_20260611_162930.csv
9. 建议封装一个通用路径工具
如果项目中很多脚本都需要读取 output、input、data 等目录,可以封装一个简单函数。
例如在项目中创建:
sample_turbine_mast_analysis
└─ utils
└─ paths.py
内容如下:
from pathlib import Path
def get_project_root() -> Path:
"""
获取项目根目录:sample_turbine_mast_analysis
当前文件位于 sample_turbine_mast_analysis/utils/paths.py
所以 parent.parent 即为项目根目录。
"""
return Path(__file__).resolve().parent.parent
def get_output_dir() -> Path:
"""
获取 output 目录。
"""
return get_project_root() / "output"
def get_output_file(filename: str) -> Path:
"""
获取 output 目录下的某个文件路径。
"""
return get_output_dir() / filename
然后在业务脚本中这样使用:
import pandas as pd
from utils.paths import get_output_file
csv_path = get_output_file("all_files_resampled_20260611_162930.csv")
print("CSV路径:", csv_path)
print("文件是否存在:", csv_path.exists())
df = pd.read_csv(csv_path, encoding="utf-8-sig")
这种写法的好处是:
- 路径逻辑集中管理;
- 每个脚本不用重复写
parents[2]; - 后续项目目录变化时,只需要改一个地方;
- 更适合多人协作和长期维护。
10. 另一个实用技巧:自动读取最新生成的文件
有些输出文件带有时间戳,例如:
all_files_resampled_20260611_162930.csv
这种文件名容易变,如果代码写死文件名,下一次重新生成文件后就可能找不到。
可以改成自动读取最新文件:
from pathlib import Path
import pandas as pd
project_root = Path(__file__).resolve().parents[2]
output_dir = project_root / "output"
csv_files = list(output_dir.glob("all_files_resampled_*.csv"))
if not csv_files:
raise FileNotFoundError(f"没有找到 all_files_resampled_*.csv 文件,目录:{output_dir}")
latest_csv = max(csv_files, key=lambda p: p.stat().st_mtime)
print("读取最新文件:", latest_csv)
df = pd.read_csv(latest_csv, encoding="utf-8-sig")
这样不需要每次手动改时间戳文件名。
11. 排查路径问题的固定模板
以后遇到路径问题,可以先加下面这段代码:
from pathlib import Path
import sys
print("=" * 80)
print("Python解释器:")
print(sys.executable)
print("\n当前工作目录 Path.cwd():")
print(Path.cwd())
print("\n当前 py 文件路径:")
print(Path(__file__).resolve())
print("\n当前 py 文件所在目录:")
print(Path(__file__).resolve().parent)
test_path = Path("../../output/all_files_resampled_20260611_162930.csv")
print("\n原始相对路径:")
print(test_path)
print("\n解析后的绝对路径:")
print(test_path.resolve())
print("\n文件是否存在:")
print(test_path.exists())
print("=" * 80)
这段代码可以快速回答三个关键问题:
- 当前 Python 解释器是不是对的;
- 当前工作目录到底在哪里;
- 相对路径最终被解析到了哪里。
只要把这三个问题搞清楚,绝大多数 FileNotFoundError 都能快速定位。
12. 最终推荐方案
对于 VS Code,可以做两层处理。
第一层,改善 VS Code 运行体验:
用户级 settings.json 中加入:
{
"python.terminal.executeInFileDir": true
}
项目级 .vscode/launch.json 中加入:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debug 当前文件目录",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${fileDirname}",
"justMyCode": true
}
]
}
第二层,代码中不要依赖 IDE 的当前工作目录,而是使用:
from pathlib import Path
project_root = Path(__file__).resolve().parents[2]
csv_path = project_root / "output" / "all_files_resampled_20260611_162930.csv"
这才是最稳的方式。
13. 总结
这次问题的核心不是文件不存在,也不是 pandas 读取 CSV 的问题,而是:
VS Code 的当前工作目录和当前 Python 文件所在目录不是一回事。
相对路径:
"../../output/xxx.csv"
看起来是从当前 .py 文件出发,但实际是从 Path.cwd() 出发。
因此,只要 VS Code 当前工作目录不是你以为的位置,路径就会找偏,最终报:
FileNotFoundError
解决这类问题,最重要的是记住一句话:
写给自己临时调试的脚本,可以调整 VS Code 的
cwd;写给项目长期使用的代码,应该基于__file__构造绝对路径。
这样才能避免同一段代码在 PyCharm 能跑、VS Code 不能跑、命令行又报错的问题。
更多推荐
所有评论(0)