handle.exe 是最直接有效的文件锁定进程查询工具,需以管理员权限运行 handle.exe -a "路径" 查看占用进程pid,加 -u 参数可捕获服务进程句柄。

用 Handle.exe 查看谁锁定了文件(最直接有效)
Windows 本身不提供标准 API 直接查“哪个进程锁了某个文件”,但 Sysinternals 的 Handle.exe 是事实标准工具——它读取内核句柄表,能精准定位。别自己写驱动或调用未公开 API,徒增复杂度和权限问题。
操作步骤:
- 从微软官网下载
Handle.exe(属于 Sysinternals 套件),解压后无需安装,直接运行 - 以管理员权限打开命令行(右键“终端(管理员)”),否则看不到系统进程的句柄
- 执行:
handle.exe -a "C:\path\to\your\file.txt",-a表示全路径模糊匹配,支持通配符 - 输出中每行类似
notepad.exe pid: 1234 type: File 60: C:\path\to\your\file.txt,其中pid就是目标进程 ID
注意:Handle.exe 默认只显示当前会话可见的句柄;若文件被服务进程(如 svchost.exe 中的某服务)锁定,需加 -u 参数提升权限上下文,否则可能漏掉。
用 GetFileInformationByHandleEx + GetFinalPathNameByHandle 判断是否被占用(C++ 运行时检测)
如果你在程序里需要“尝试访问前预判”,而不是事后排查,GetFileInformationByHandleEx 配合 GetFinalPathNameByHandle 可间接验证——但注意:它不能告诉你谁锁的,只能告诉你“此刻能否打开”。
典型误用是直接调 CreateFile 看 ERROR_SHARING_VIOLATION,但这只是结果,不是原因。更稳妥的做法:
- 先用
CreateFile以GENERIC_READ和FILE_SHARE_READ | FILE_SHARE_WRITE打开,失败则大概率被独占占用 - 若成功,立刻调
GetFileInformationByHandleEx(hFile, FileNormalizedNameInfo, ...)或GetFinalPathNameByHandle确认句柄确实指向目标路径(防符号链接绕过) - 立即
CloseHandle,避免自己变成新占用者
这个流程不能反向查进程,但它能帮你把“打开失败”的错误归因到“共享冲突”,排除路径不存在、权限不足等干扰项。
为什么不用 NtQuerySystemInformation 或 EnumProcesses 自己遍历?
理论上可行,但实际踩坑极多:你需要对每个进程调 OpenProcess → EnumProcessHandles → 对每个句柄调 GetHandleInformation + GetFinalPathNameByHandle,而大部分进程你根本没权限打开(尤其 lsass.exe、winlogon.exe),一调就 ACCESS_DENIED,返回空结果容易误判为“没人占用”。
更麻烦的是句柄类型过滤——文件句柄只是其中一种,还有事件、互斥体、注册表键等,GetHandleInformation 不返回类型,必须用未公开的 NtQueryObject + ObjectTypeInformation,稳定性差,Win11 已有兼容性问题。
所以除非你在写杀毒软件或调试器,否则真没必要碰这套。Sysinternals 的 Handle.exe 底层也是用类似机制,但它已处理好权限降级、异常捕获和类型解析,复刻成本远高于收益。
PowerShell 脚本快速辅助定位(开发/运维现场应急)
如果没法立刻用 Handle.exe,又需要脚本化排查,PowerShell 的 Get-Process + Get-ChildItem 组合虽不准,但在某些场景下够用:
-
Get-Process | Where-Object { $_.Path -like "*filename*" } | Select-Object Id, ProcessName, Path—— 查进程路径含文件名的(仅适用于程序路径里带文件名的情况,比如启动时传参) -
net file—— 仅对通过 SMB 共享被打开的文件有效,且要求本地是 Server 服务角色(默认 Win10/11 关闭) - 真正可靠的还是:
Start-Process -FilePath "handle.exe" -ArgumentList "-a", "C:\target.txt" -Verb RunAs,强制提权调用
别信网上那些用 WMI Win32_Process 查 CommandLine 匹配路径的方案——现代应用几乎都不把文件路径塞进命令行,而且 WMI 查询本身就有延迟和采样丢失。
最常被忽略的一点:文件被“锁定”不等于被“打开”。例如一个进程调用了 CreateFile 后忘了 CloseHandle,句柄泄漏;或者用了 FILE_FLAG_DELETE_ON_CLOSE 但还没真正删除——这时候 Handle.exe 依然能扫出来,但进程列表里找不到明显关联行为。得结合句柄的 GrantedAccess 字段(handle.exe -p PID 查具体句柄)和进程生命周期一起看。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











