最直接有效的方式是用 os.open(path, os.O_EXCL | os.O_RDWR) 独占打开文件:成功说明未被写占用,抛出 PermissionError(Windows)或 OSError(含 errno.EBUSY)则很可能被占用,且需立即 close()。

用 os.open() 尝试独占打开文件
最直接有效的方式是尝试以独占模式打开文件,而不是读取内容。Windows 下文件被占用时,os.open() 会抛出 PermissionError;Linux/macOS 下则可能返回 EBUSY 或 EACCES,但更常见的是 O_EXCL 不生效,所以优先在 Windows 上用此法。
关键点:必须用 os.O_EXCL | os.O_RDWR(或至少 os.O_WRONLY),只读打开(os.O_RDONLY)几乎总能成功,无法判断占用。
-
os.open(path, os.O_EXCL | os.O_RDWR)成功 → 文件未被其他进程以写方式占用 - 抛出
PermissionError(Windows)或OSError(含errno.EBUSY)→ 很可能被占用 - 注意:即使打开成功,也要立刻
os.close(),否则你自己就占用了它
Windows 下用 psutil 查进程句柄
当需要知道“谁在占用”,而不仅是“是否被占用”时,psutil 是唯一靠谱的跨进程检查手段。它通过遍历所有进程的打开文件句柄来定位。
实操上,psutil.process_iter() + proc.open_files() 是核心组合,但性能开销大——尤其对大文件路径,需做字符串归一化(如用 os.path.realpath() 统一路径格式),否则容易匹配失败。
立即学习“Python免费学习笔记(深入)”;
- 务必捕获
psutil.AccessDenied和psutil.NoSuchProcess异常,普通用户无法读取系统进程句柄 - 避免在循环中反复调用
os.path.realpath(),提前计算好目标路径的规范形式 - 示例逻辑:
target = os.path.realpath(path)<br>for proc in psutil.process_iter(['pid', 'name']):<br> try:<br> for file in proc.open_files():<br> if os.path.realpath(file.path) == target:<br> print(f"PID {proc.pid} ({proc.name()}) holds it")<br> except (psutil.AccessDenied, psutil.NoSuchProcess):<br> pass
Linux/macOS 下没有通用可靠方案
Unix 系统本身不阻止多进程同时读取同一文件,所谓“占用”通常指写入锁定(如 flock)或内存映射(mmap)。因此,不存在 Windows 那种全局文件锁语义。
这意味着:lsof 或 /proc/*/fd/ 扫描只能发现显式打开该文件的进程,但无法判断是否被 mmap、日志轮转工具、数据库引擎等隐式持有。而且 lsof 输出路径可能带符号链接,匹配前必须解析真实路径。
- 不要依赖
lsof -f -- <path></path>的返回码判断占用与否——它可能根本查不到任何结果,但文件依然被某个 mmap 进程锁定 -
fuser -v <path></path>更轻量,但同样受限于内核是否暴露句柄信息 - 真正稳健的做法是:业务层自己加锁(如用
os.open(..., os.O_CREAT | os.O_EXCL)创建锁文件),而非依赖 OS 级占用检测
别用 open(..., 'r') 判断占用
这是最常见的误操作。Python 的 open() 默认只读模式在绝大多数情况下都能成功打开一个被其他进程写的文件(尤其是日志类大文件),完全无法反映真实占用状态。
原因在于:POSIX 允许并发读;Windows 的共享读默认开启;且 Python 层不校验底层句柄是否可写/是否被独占锁住。
- 即使
open(path, 'r')成功,后续f.write()仍可能因权限或锁失败 - 试图用
open(path, 'r+')也不可靠——某些场景下(如被记事本打开)仍会成功,但写入时才报错 - 结论:任何基于
open()的读/写尝试,都不能替代真正的独占打开或句柄扫描
实际场景里,Windows 用户优先用 os.open(..., os.O_EXCL | os.O_RDWR) 快速探路;跨平台或需溯源时,再引入 psutil 并做好异常兜底。Linux 下与其花力气猜谁在用,不如推动上游服务用文件锁协议协作。


















