删一个文件,Windows 却告诉你"另一个程序正在使用此文件"。于是你关掉眼前能看见的窗口,回来再删,还是删不掉。这篇文章把这件事讲透:锁到底加在哪一层、系统给的几种报错分别是谁在报、怎么查出真正持锁的那个进程,以及哪些"强删"办法其实是在给自己挖坑。文中的规则全部引自微软官方文档的中文页,错误提示原文与共享模式对照表来自一台 Windows 10 专业版 22H2(内部版本 19045.6466)实机的复现结果。

信息核验时点:2026-11-01(Sysinternals Handle v5.0,发布时间 2022 年 10 月 26 日;Process Explorer v17.2,发布时间 2026 年 10 月 15 日)


本文要点
  • 一句话定义:文件占用是某个程序手里还攥着这个文件的句柄,而 Windows 在句柄关闭之前会拒绝删除和重命名——微软对这条规则的原话是"该句柄一直有效,直到应用程序关闭句柄或终止"。
  • 核心结论:删不掉不是权限问题,而是锁没放。先分清报错出自哪一层,再用 Handle 或进程资源管理器按文件名反查持锁进程,让那个进程退出(实机验证:持锁进程结束后删除立刻成功),比任何"强制删除工具"都安全。
  • 适用场景:清理旧文件、批量改名、删整个文件夹时被里面某一个文件卡住,以及共享盘里的文件提示"正由另一进程使用"。
  • 适用人群:经常要归档和清理文件的办公人群,尤其是被"删不掉又不能不管"卡住、又不敢乱装工具的人。
  • 短板/边界:查句柄的两款 Sysinternals 工具都需要管理员权限,其中进程资源管理器当前版本的客户端要求是 Windows 11 及更高;Windows 自带的 openfiles 默认看不到本地文件句柄,要改系统全局标志并重启,代价不划算。

"文件正在被另一个程序使用"到底是什么机制?

结论先给:这是文件句柄上的共享锁,不是权限不够。

程序要用一个文件,得先向系统申请一个句柄。微软在讲内核对象的文档里写了它的生命周期:"该句柄一直有效,直到应用程序关闭句柄或终止。"(Microsoft Learn:内核对象)同一页还给了另一条更关键的说法:"只要至少有一个对象句柄存在,对象就保留在内存中。"(同上页)也就是说,只要还有一个句柄没关,这个文件在系统眼里就是"正在被使用"。

锁的松紧,由打开文件时申请的共享模式决定。CreateFile 这个 Win32 函数把它写得很清楚:"请求的文件或设备的共享模式,可以读取、写入、删除、所有这些或无(请参阅下表)。"(Microsoft Learn:CreateFileW 函数)而冲突的后果是:"无法请求与具有打开句柄的现有请求中指定的访问模式冲突的共享模式。CreateFile 将失败,GetLastError 函数将返回 ERROR_SHARING_VIOLATION。"(同上页)

ERROR_SHARING_VIOLATION 就是错误码 32,官方错误码表给的中文说明是:"进程无法访问该文件,因为它正在被另一个进程使用。"(Microsoft Learn:系统错误代码 (0-499))同一张表里紧挨着还有一条容易混淆的:错误码 33 的 ERROR_LOCK_VIOLATION 写作"另一个进程已锁定了文件的一部分,因此进程无法访问该文件。"(同上页)——32 是整个文件被别人占着,33 是文件里某一段区间被锁;日常办公遇到的"删不掉"绝大多数是前者。

还有一条容易被忽略、但决定了整篇文章做法的规则:"注意 每个打开句柄的共享选项一直有效,直到该句柄关闭,而不考虑进程上下文。"(同 CreateFileW 页)注意"不考虑进程上下文"这几个字——它意味着锁不是"别人"的专利:你自己开的程序、你自己以管理员身份开的命令行,同样会被上一个还没关闭的句柄挡住。

同一件事为什么有几种不同的报错文案?

因为报错的层不一样。下面这几条都在一台 Windows 10 专业版 22H2(内部版本 19045.6466)的实机上复现过:让一个进程以独占方式打开一个文本文件不放,再分别用几种方式删它、改它。

你用的操作实机返回的提示出自哪一层
cmd 的 del、ren另一个程序正在使用此文件,进程无法访问。Win32 错误 32
按资源管理器那套 shell 方式删除(移到回收站)另一个程序正在使用此文件,进程无法访问。同一条系统消息
PowerShell 的 Remove-Item无法删除项 …\busy.txt: 文件"…\busy.txt"正由另一进程使用,因此该进程无法访问此文件。.NET 的 IOException
PowerShell 的 Move-Item、Rename-Item另一个进程正在使用此文件,因此该进程无法访问此文件。Win32 错误 32
[System.IO.File]::Delete文件"…\busy.txt"正由另一进程使用,因此该进程无法访问此文件。.NET 的 IOException

几种说法指的是同一件事,但有两点值得记住。

第一,报错只告诉你"哪个文件"被占用,不告诉你"哪个进程"占用了它。上面这几条提示里出现的只有文件名和路径,没有一个进程名——这正是后面要借助工具的原因。

第二,锁的粒度比"删除"更宽。实机上,被独占打开的文件不只是删不掉:复制到别处(Copy-Item)、原地覆盖写入(Set-Content)、改名,全部返回同一句"正由另一进程使用"。改名和删除被一起挡,官方在 CreateFileW 页的 FILE_SHARE_DELETE 条目里给了说法:"注释 删除访问权限允许删除和重命名操作。"(同 CreateFileW 页)

为什么"我只是打开看了一眼"也会挡住删除?

因为决定成败的不是"看没看",而是持锁的那次打开有没有把"允许别人删除"让出去。

把实机复现的结果列成表更直观。做法都一样:另一个进程以某种共享模式打开文件不放,然后在本机执行删除。

持锁方打开时给的共享模式删除结果
不给任何共享(独占)删不掉
只允许别人读删不掉
只允许别人写删不掉
同时允许读和写删不掉
允许别人删除删掉了,而且文件当场从目录里消失

差别就在最后那一行。FILE_SHARE_DELETE 的官方定义是:"启用对文件或设备上的后续打开操作以请求删除访问权限。否则,如果文件或设备请求删除访问权限,则任何进程都无法打开该文件或设备。"(同 CreateFileW 页)而独占那一档写得更硬:"如果此参数为零且 CreateFile 成功,则文件或设备无法共享,并且无法在文件或设备的句柄关闭之前再次打开。"(同上页)换句话说,只要持锁的程序没在打开时把删除这一项让出来,谁都删不动它。

至于"文件已经删掉了,但那个程序还在读它"这种看起来矛盾的情况,官方页也交代了:句柄选项"一直有效,直到该句柄关闭"(同上页),也就是说那个进程手里的句柄仍然可用,直到它自己关闭;但目录里已经看不见这个文件了。实机验证过这一点——删除成功后立刻检查路径存在性,结果是"不存在",而持锁进程还在运行。

对普通办公场景,这张表有一个很实用的推论:一个程序只是"打开着这个文件",就足以让你删不掉;而它到底给不给删除留口子,是程序自己写死的,用户在界面上没法选。所以真正能做的,是让持锁的那个进程退出。

怎么查出是哪个程序占用了文件?

三条路,前两条要下载微软自家的 Sysinternals 工具,第三条用系统自带命令。

第一条:Handle,命令行按文件名反查。 官方页开头就是为这件事写的:"有没有想过哪个程序打开了特定的文件或目录? 现在可以了解了。Handle 是一个实用工具,用于显示有关系统中任何进程的打开句柄的信息。"(Microsoft Learn:Handle)当前版本是 Handle v5.0,发布时间 2022 年 10 月 26 日,安装包 729 KB(同上页)。用法页给了直接按名字搜的例子:"例如,如果想要知道哪个进程(如果有)打开了"c:\windows\system32",则可以键入:handle windows\system"(同上页),并且说明"名称匹配不区分大小写,指定的片段可以是路径中你感兴趣的任意位置。"(同上页)——所以不必输全路径,文件名里的一段就够。

用之前有两句官方提示要当回事。一句是权限:"通过键入"handle"运行 Handle。 必须具有管理权限才能运行 Handle。"(同上页)另一句是关于直接关句柄的:"-c 关闭指定的句柄(解释为十六进制数)。 必须通过其 PID 指定进程。警告:关闭句柄可能会导致应用程序或系统不稳定。"(同上页)这条警告也是本文后面"不建议强关句柄"的依据。

顺带两个能省事的参数:-u 是"搜索句柄时显示拥有用户名"(同上页),持锁的常常是另一个登录账户跑着的服务;-p 则把扫描范围收窄,官方说明是"此参数不会检查系统中的所有句柄,而是将 Handle 的扫描范围缩小到以名称进程开头的进程"(同上页),怀疑对象明确时能快很多。

第二条:进程资源管理器,图形界面里搜。 官方介绍的说法是:"进程资源管理器可显示有关打开或加载了哪些句柄和 DLL 进程的信息。"(Microsoft Learn:进程资源管理器)界面怎么读它也写清了:"顶部窗口始终显示当前活动进程的列表,包括其所属帐户的名称,而底部窗口中显示的信息取决于进程资源管理器所处的模式:如果它处于句柄模式,你将看到顶部窗口中选择的进程已打开的句柄;如果进程资源管理器处于 DLL 模式,则会看到进程已加载的 DLL 和内存映射文件。"(同上页)反过来按文件找进程更省事,官方原话是:"进程资源管理器还具有强大的搜索功能,可快速显示哪些进程打开了特定的句柄或加载了 DLL。"(同上页)当前版本 v17.2,发布时间 2026 年 10 月 15 日,安装包 3.5 MB,安装方式一句话就够:"只需运行进程资源管理器 (procexp.exe)。"(同上页)

选它之前先看版本边界,官方页"运行于:"这一节按客户端和服务器分别列出:「客户端:Windows 11和更高。」「服务器:Windows Server 2019及更高。」(同上页)还在用 Windows 10 的朋友这一条要留意——本站Windows 10 和 Windows 11 怎么选里也提过,系统版本会直接决定你能用哪些工具。

第三条:系统自带的 openfiles,但它默认看不到本地句柄。 openfiles 的官方定位是:"使管理员能够查询、显示或断开系统上打开的文件和目录的连接。 此命令还启用或禁用系统 维护对象列表 全局标志。"(Microsoft Learn:openfiles)

关键在这个全局标志。官方页写得很直白:"默认情况下,禁用 维护对象列表 全局标志,并显示以下消息 INFO: The system global flag 'maintain objects list' is currently disabled."(同上页)实机上执行 openfiles /query,得到的正是这条提示的中文版:「信息: 需要启动系统全局标志“维护对象列表”才能查看本地打开的文件。」(原文分三行显示,后面还附一句「请参阅 Openfiles /? 以获得详细信息。」)同一次执行另有一行「错误: 拒绝访问。」——也就是说这台机器上,既没开全局标志,也还没提到管理员权限;两件事叠加,这条命令在本地自然什么都列不出来。

那要不要为这件事打开它?官方给了两个代价:"使用 "打开 "或 "关闭 "选项所做的更改在重新启动系统之前不会生效。 启用 维护对象列表 全局标志可能会减慢系统速度。"(同上页)为删一个文件去动一个需要重启、还会拖慢系统的全局开关,不划算。它的正确用途是下面共享盘那一节——那里它默认就能用。

找到占用者之后,怎么把锁放掉?

按代价从小到大排三步。

  1. 先回到那个程序里正常关闭文件。文档类文件优先在应用内关闭标签或退出程序,这比杀进程干净。
  2. 应用没窗口可关、或者关了还在占用,就结束它的进程。PowerShell 里可以按名字来:"Stop-Process cmdlet 停止一个或多个正在运行的进程。 可以按进程名称或进程 ID(PID)指定进程,也可以将进程对象传递给 Stop-Process。"(Microsoft Learn:Stop-Process),官方示例 1 就是 Stop-Process -Name "notepad",说明是"此命令停止计算机上的记事本进程的所有实例。"(同上页)。同一页也标了两条边界:一条是"Stop-Process 仅适用于在本地计算机上运行的进程。"(同上页),另一条是"在 Windows Vista 和更高版本的 Windows 操作系统上,若要停止当前用户不拥有的进程,必须使用"以管理员身份运行"选项启动 PowerShell。"(同上页)
  3. 前两条都不奏效,就重启。这一步的依据是本文开头那条规则——句柄随进程终止而失效(同内核对象页)。实机上验证过这条完整链路:持锁进程被结束后,立刻重跑刚才失败的那条 Remove-Item,删除成功。

这三步的共同点是:让持锁的程序自己把句柄关掉,而不是绕过它。Handle 的 -c 可以强行关闭指定句柄,但官方对它的警告是"关闭句柄可能会导致应用程序或系统不稳定"(同 Handle 页),而且它"必须通过其 PID 指定进程"(同上页)——PID 和十六进制句柄值配错一对,关掉的可能是别的对象。

删文件夹时,为什么一个文件卡住整个目录?

因为删目录要先删空它。实机上对一个内部含被占用文件的目录执行递归删除,返回的提示直接点名了里面那个文件:"无法删除项 …\busy.txt: 文件"busy.txt"正由另一进程使用,因此该进程无法访问此文件。"

这条提示比删单文件时更有用:它告诉你是目录里的哪一个文件在挡路。拿着这个文件名去用 Handle 搜(同上文第一条),命中率比拿目录名去搜高得多。

批量清理时这个坑尤其常见。本站别再建"新建文件夹(2)"了:一套能让你 3 秒定位任何历史文件的命名与归档法里那套归档流程,最后一步就是删空目录;如果每次都卡在这里,问题通常不在归档方法,而在有几个程序一直开着里面的文件。用 DropIt 这类按规则批量搬文件的工具时也一样——批量移动做的仍然是移动,而实机上移动和改名同样会被独占锁挡下(见上文对照表),所以卡住时按文件名去查占用,比反复重跑规则有用。本站DropIt 文件自动整理讲过它的批处理动作怎么配。

共享盘里的文件删不掉,怎么确认是谁开着?

这是 openfiles 真正的主场。它"使管理员能够查询、显示或断开系统上打开的文件和目录的连接"(同 openfiles 页),共享盘上的打开记录不需要那个全局标志——上一条里默认关闭的是本地文件句柄的追踪。

查询用 openfiles /query,官方对这部分的标题就是一句"查询并显示所有打开的文件。"(同上页),示例写法为"若要查询并显示所有打开的文件,请键入:openfiles /query"(同上页)。它也支持远程主机,/s 参数的说明是"指定要连接到的远程系统(按名称或 IP 地址)。 不要使用反斜杠。 如果不使用 /s 选项,则默认情况下该命令在本地计算机上运行。"(同上页)输出格式可以用 /fo,官方列出的三个有效值依次是「TABLE - 在表中显示输出。」「LIST - 以列表形式显示输出。」「CSV - 以逗号分隔值 (CSV) 格式显示输出。」(同上页)

确认是谁开着之后断开。/disconnect 一节的定位是"使管理员能够断开通过共享文件夹远程打开的文件和文件夹的连接。"(同上页)四种定位方式各对应一个参数:按文件 ID、按访问者用户名、按打开模式、按打开的文件名(同上页)。官方给的例子最直观:

  • "要断开用户 hiropln 访问的所有打开的文件和目录,请键入:openfiles /disconnect /a hiropln"(同上页)
  • "若要断开目录与打开的文件名 C:\testshare 的连接,无论谁正在访问它,请键入:openfiles /disconnect /a * /op c:\testshare\"(同上页)

需要提醒的是,/disconnect 是拿别人的工作现场开刀:对面那个人正在编辑的文件会被强制断开。先打招呼,再执行。

另外,中文页的参数表里有几个开关名被机器翻译改了字(比如把 /a 写成"一个"、把 /op 写成"作"),上面引用的两条官方示例才是可以直接照抄的写法;要查参数含义时建议对照同一页的英文原文。

哪些"强制删除"的做法不建议用?

  1. 强关句柄。Handle 的 -c 参数自带官方警告:"关闭句柄可能会导致应用程序或系统不稳定。"(同 Handle 页)它适合专家定位问题,不适合当成日常删除手段。
  2. 见进程名不认识就结束任务。上一节那条 Stop-Process 只该用在你已经查出持锁的那个进程上。官方页对此有一句分量很重的提醒:"停止进程时,意识到停止进程可以停止依赖于进程的进程和服务。 在极端情况下,停止进程可能会停止 Windows。"(同 Stop-Process 页)
  3. 为查本地句柄去开"维护对象列表"全局标志。官方写明了两个代价:改完要重启才生效,而且"启用 维护对象列表 全局标志可能会减慢系统速度"(同 openfiles 页)。
  4. 装来路不明的"文件解锁/强制删除"小工具。这类工具做的事情无非是枚举句柄或强关句柄,微软自家的 Handle、进程资源管理器已经覆盖,而且官方页可直接下载(同 Handle 页、同进程资源管理器页)。本站Windows 自带工具和官方小工具清单里也坚持同一个口径:能走官方渠道就不装二手工具。
  5. 用"改扩展名""改系统时间"这类流传的偏方。它们既不能释放句柄,又会把文件属性弄乱;真正卡住的是内核对象,跟文件名后缀无关。

顺带说一句定位技巧:如果你连文件的确切路径都记不清,先用 Everything 按文件名搜出完整路径,再拿路径里的一段去喂 Handle,本站Everything 文件搜索讲过它的用法。

常见问题

提示"另一个程序正在使用此文件",是权限不够吗?

不是。权限不够时系统给的是"访问被拒绝"那一类提示,而这条提示对应错误码 32、ERROR_SHARING_VIOLATION,官方的中文说明是"进程无法访问该文件,因为它正在被另一个进程使用。"(同系统错误代码页)。实机上以管理员身份删一个被别的进程独占打开的文件,返回的仍是"正由另一进程使用"。判断依据很简单:提示里出现"使用""占用"字样,就先去找持锁的进程,别去改安全选项卡。

关掉所有看得见的窗口还是删不掉,怎么办?

因为持锁的不一定有窗口。Handle 显示的是"系统中任何进程的打开句柄的信息"(同 Handle 页),进程资源管理器"顶部窗口始终显示当前活动进程的列表,包括其所属帐户的名称"(同进程资源管理器页),后台进程和服务都跑不掉;Handle 加 -u 还能"搜索句柄时显示拥有用户名"(同 Handle 页)。查不出来又不赶时间的话,重启是最省事的一条:句柄随进程终止失效(同内核对象页),实机上结束持锁进程后删除立刻成功。

为什么复制到别处也不行?我以为只有删除会被挡。

因为共享模式管的是"允许别人以什么方式再打开这个文件",读取也在其中。实机上,被独占打开的文件连 Copy-Item 都会返回同一句"正由另一进程使用";改名同样被挡,官方的说法就是"删除访问权限允许删除和重命名操作"(同 CreateFileW 页)。所以"先复制走再删原件"这条常见思路,在独占锁面前走不通。

用 Handle 关句柄快,还是结束进程快?

结束进程。Handle 的 -c 确实能直接"关闭指定的句柄(解释为十六进制数)",但官方紧跟一句"警告:关闭句柄可能会导致应用程序或系统不稳定"(同 Handle 页)。相比之下,让持锁进程正常退出或按名字结束它(同 Stop-Process 页)走的是系统自己的清理路径,句柄会随进程一起释放。只有在"这个进程绝不能退出、但那个文件的句柄可以放掉"这种极少见场景下,才轮到强关句柄。

服务器共享盘上有人挂着文件,管理员能直接断开吗?

能,用 openfiles /disconnect,按文件 ID、访问者用户名、打开模式或打开的文件名四种方式定位(同 openfiles 页)。但这是对别人正在使用的连接动手,对面未保存的修改可能丢失。先联系当事人再执行;要批量断开某个共享目录的所有连接,官方给的写法是"openfiles /disconnect /a * /op c:\testshare\"(同上页)。

复制文件时提示"另一个进程已锁定了文件的一部分",和"正由另一进程使用"是一回事吗?

不是同一条。官方错误码表里,错误码 32 是"进程无法访问该文件,因为它正在被另一个进程使用",错误码 33 的 ERROR_LOCK_VIOLATION 写作"另一个进程已锁定了文件的一部分,因此进程无法访问该文件"(同系统错误代码页)。前者是整个文件的共享冲突,后者是文件内部某段字节区间被锁——通常出现在下载工具、虚拟机磁盘、数据库文件这类"边写边锁"的程序身上。处理办法一样:找出持句柄的进程,让它退出。

结尾:先做这三件事

下次再遇到"删不掉",按这个顺序走,两分钟之内能到结论。

  1. 记下提示里的文件名。几种报错都会点名具体文件,删目录时报错还会点名目录里挡路的那一个(见上文实机结果)。
  2. 用 Handle 按文件名搜一次,管理员身份运行;查出来是认识的程序就正常关闭,关不掉再按名字结束进程;实在查不到就重启。
  3. 把"强关句柄"和"来路不明的强制删除工具"从习惯里划掉。需要长期处理共享盘占用,学的是 openfiles /query 与 /disconnect 那几种定位方式,而不是装新工具。

锁的规律就一句话:句柄没关,文件就删不动。工具只是帮你找到那只还没松开的手。

本文数据核验于 2026-11,以官方 Release Notes/文档为准。

发表评论

验证码图片,点击可更换