FileNotFoundError 文件不存在:Errno 2 No such file or directory 速查
更新时间:2026-10-24。FAQ 速查页,面向一跑脚本就撞
FileNotFoundError的同学——尤其是「文件明明就在那儿,为什么 Python 说没有」这类最气人的场景。这个报错字面上只有一句话「这个路径不存在」,但「不存在」的真因分六根轴:相对路径相对的是工作目录而不是脚本所在目录(占一半以上)、路径字符串本身拼错或转义翻车、软链接指向的目标没了、大小写敏感在换系统后咬人、文件压根没提交/没同步到这台机器、以及中间某一级目录缺失。报错原文里那个被引号括起来的路径就是全部线索,拿它和磁盘真身对一遍基本必中。文件在但没权限碰归 PermissionError 权限被拒速查 管。
本文要回答的问题
- 文件就在脚本旁边,为什么
open('data.csv')报 Errno 2? - 为什么 IDE 里跑得好好的,命令行一跑就找不到文件?
__file__定位法怎么写才稳?- 路径在 Windows 能跑、到 Linux 就报不存在,是为什么?
- 怎么一眼分辨是「路径指错」还是「文件真没传上来」?
一、报错原文与典型现象
报错就长在 traceback 最后一行,引号里的路径是排查起点(工程路径以 /proj/demo 占位):
$ python3 /proj/demo/src/main.py
Traceback (most recent call last):
File "/proj/demo/src/main.py", line 3, in <module>
open("data/users.csv").read()
FileNotFoundError: [Errno 2] No such file or directory: 'data/users.csv'
# 文件在 /proj/demo/data/users.csv——但你当前的工作目录不是 /proj/demo$ python3 /proj/demo/read.py
FileNotFoundError: [Errno 2] No such file or directory: '/proj/demo/config/Config.yaml'
# 磁盘上真身是 config.yaml——大小写差了$ ls -l /proj/demo/data
lrwxrwxrwx 1 user user 18 Oct 24 09:00 latest -> /proj/demo/release/v3
# 软链 latest 指向的 v3 目录已被清理——链接本身在、目标没了读报错先做一个动作:把引号里的路径原样复制,ls 一下。ls 也说不存在,是路径或文件真身的问题;ls 说存在而 Python 说不存在,几乎只剩软链失效和权限两级目录不可进这两种偏门(后者其实是 PermissionError,但偶发混报)。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| IDE 能跑、命令行不能 | 相对路径以工作目录为锚,两边锚不同 | 代码里打印 os.getcwd() | 用 __file__ 定位法改绝对锚 |
| 相对路径报不存在 | 工作目录不是你以为的那个 | pwd 对比脚本目录 | cd 到项目根跑,或改 __file__ 法 |
| 路径肉眼看着对就是找不到 | 大小写差异(Config.yaml vs config.yaml) | ls 目录 逐个字符核对 | 改代码路径与磁盘完全一致 |
路径含 \ 或 \t 类怪字符 | Windows 路径反斜杠被当转义 | 打印 repr(路径) 看真身 | 用原始字符串 r"..." 或正斜杠 |
ls 文件在、打开报不存在 | 软链目标被删( dangling symlink ) | ls -l 看链接目标是否标红 | 重建链接或指到现存目标 |
| 本地能跑、服务器不能 | 文件没 git 提交 / rsync 没同步 | 服务器上 ls 核对 | 提交入库或补同步;git 里加白名单 |
| 报错路径是中间某级目录 | 父目录不存在,open(...,"w") 不会自动建 | 逐级 ls 报错路径 | 写前 os.makedirs(目录, exist_ok=True) |
| cron/systemd 里必报、手跑正常 | 守护进程工作目录是 / 或家目录 | 日志里打印 cwd | 脚本内用 __file__ 绝对化所有路径 |
三、排查决策图
下面这张图是文件不存在类报错的标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住一个分水岭:先把报错原文里的路径原样 ls。ls 也找不到,问题在「路径与文件真身」这层(拼写、大小写、没同步、软链);ls 找得到而 Python 找不到,问题几乎必然在「锚点」——你的相对路径被拼到了另一个工作目录上。两分的这一步能砍掉一半的瞎猜。
四、逐条排查展开
第一病因:相对路径相对的是「工作目录」,不是「脚本目录」。 这是 Errno 2 的半壁江山。open("data/users.csv") 会被拼成 os.getcwd() + "/data/users.csv",而 cwd 取决于你在哪敲的命令:IDE 通常把项目根设为 cwd,命令行是你当前站着的目录,cron 里是 / 或服务账户家目录——同一份代码三个锚点,自然有的环境炸有的不炸。确认:
import os
print(os.getcwd()) # 在报错环境里打,不是在你以为的环境里根治方案:__file__ 定位法,让路径跟着代码走。 不管从哪跑,都以脚本自身位置为锚拼绝对路径:
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent # 项目根,按层级调整
data_path = BASE_DIR / "data" / "users.csv"
with open(data_path) as f:
...resolve() 顺手把软链解析成真身。项目里所有资源路径都从 BASE_DIR 派生,cwd 是什么都与你无关——这是工业界 Python 项目的标准写法,写进项目模板。
大小写敏感:换系统才咬人的暗坑。 Windows 和 macOS 默认文件系统大小写不敏感,Config.yaml 写成 config.yaml 也能打开;一到 Linux(服务器、容器、CI)立刻 Errno 2。特征:本地全绿、上服务器就炸。核对别靠肉眼,ls 目录 后逐字符对。预防:团队约定文件名全小写加连字符,从源头消灭大小写排列组合。
路径字符串的转义翻车。 Windows 路径 "C:\proj\demo\test.csv" 里的 \t 会被 Python 解释成制表符,\p、\d 原样保留——打印出来肉眼难辨,repr() 才现形:
p = "C:\proj\demo\test.csv"
print(repr(p)) # 'C:\\proj\\demo\test.csv' —— \t 变成了制表符处置三选一:原始字符串 r"C:\proj\demo"、全部换正斜杠(Windows API 认 /)、或干脆 pathlib.Path,跨平台代码首选后者。
软链失效:链接在、目标没了。 ls 看到 latest -> /proj/demo/release/v3 就认为文件在,是被链接本身骗了——目标 v3 被清理后,穿过链接的任何 open 都报 Errno 2。确认:ls -l 里链接目标标红(或 readlink -f 路径 看解析结果是否存在)。处置:把链接重指到现存版本(ln -sfn /proj/demo/release/v4 latest),发布脚本里链接切换和旧版本清理要做成原子的一对操作。
「文件没传上来」比想象中常见。 本地能跑、服务器不能,先怀疑同步链路:数据文件被 .gitignore 挡了没提交(git check-ignore -v 路径 一锤定音)、rsync 命令漏了子目录、Docker 构建时 .dockerignore 把它排除了、模型文件太大根本没人传。处置按链路补:要进版本库的解除 ignore,运行时生成的大文件写进部署清单,容器场景核对 .dockerignore 与 Dockerfile 的 COPY 段。
写文件也报 Errno 2:缺的是父目录。 open("/proj/demo/out/2026/result.csv", "w") 不会替你建 out/2026/,父目录缺一级就报不存在——这对「写」反直觉,因为缺的是目录不是文件。一行根治:
Path(路径).parent.mkdir(parents=True, exist_ok=True)所有写文件的入口前都补上这一句,日志、报表、临时文件同理。
五、规范做法与预防
- 项目模板内置
__file__定位法:BASE_DIR 派生一切资源路径,新人第一行代码就不踩 cwd 坑。 - 路径集中到一个 config 模块:全项目 import 同一份路径常量,改目录只改一处。
- 文件名全小写约定:入库规范写死,大小写问题在 CR 阶段拦截。
- 写文件前 mkdir -p:
Path(...).parent.mkdir(parents=True, exist_ok=True)当肌肉记忆。 - 发布清单核对数据文件:README 列明「运行时依赖的非代码文件」,部署脚本校验存在性。
- cron/systemd 服务里打印 cwd 与关键路径:首次部署跑一次,环境差异当场现形。
这一篇在知识体系里的位置
本篇是 Python 排错速查簇的路径篇,定位「文件真不在你指的那个位置」:文件在但没权限碰看 PermissionError 权限被拒速查;模块导入路径找不到看 ModuleNotFoundError 模块找不到速查;解释器版本不兼容看 Python 版本不兼容报错速查;装包失败看 pip install 安装失败速查;pathlib 与文件操作的概念底座看 Python 入门导览。ls 原路径 + os.getcwd() + __file__ 三件确认套在一切路径类报错里通用。
一句话总结
FileNotFoundError 先把报错引号里的路径原样 ls:也找不到就查拼写、大小写(换 Linux 高发)、软链失效(readlink -f 看真身)与同步链路(git check-ignore / rsync 漏传);ls 找得到就是锚点错——相对路径相对的是工作目录不是脚本目录,IDE、命令行、cron 三个锚点各不同。根治用 __file__ 定位法从 BASE_DIR 派生绝对路径,写文件前 mkdir(parents=True, exist_ok=True),路径集中配置、文件名全小写,这个报错基本绝迹。