发布于2026-07-08 阅读(0)
扫一扫,手机访问
判断文件是否被其他进程独占,这事儿在Windows上其实没有太直接的捷径。你可能会先想到File.Exists或者File.GetAttributes,但它们只告诉你文件存不存在、属性如何,锁状态完全不管。真正靠谱的做法,还是用FileStream模拟一次真实访问——用你后续要用的那套FileShare模式去尝试打开,能打开就没被占,抛了IOException(HResult == -2147024864或消息里说“正由另一进程使用”)那就是被占了。

FileStream 尝试打开文件是最可靠的检测方式Windows没有公开的API能直接查询“某文件当前是否被其他进程独占”,File.Exists 或 File.GetAttributes 都无法反映锁状态。唯一可信赖的做法是模拟真实访问:用 FileStream 以你后续要使用的相同 FileShare 模式去尝试打开——成功即未被占用,抛出 IOException(且 HResult == -2147024864 或消息含“正由另一进程使用”)即被独占。
注意:不能只捕获 UnauthorizedAccessException,因为权限不足和文件被占用都会触发它;必须检查异常的具体错误码或消息内容。
FileShare.Read 模式下打开失败,说明有进程以 FileShare.None 或未包含 Read 的方式持有句柄FileShare.Read 或更宽松的模式尝试,否则即使读取成功,写入时仍会失败Task.Run 或定时器做轻量探测IOException 的 HResult 和消息需双重校验.NET 中文件被占用抛出的 IOException 在不同系统版本、.NET 版本下表现不一致:HResult 可能是 -2147024864(即 0x80070020),也可能是 -2147024865(0x8007001F);英文系统提示“The process cannot access the file...”,中文系统则为“另一个程序正在使用此文件,进程无法访问”。仅依赖其中一种判断容易漏判。
实操建议:
ex.HResult == unchecked((int)0x80070020)(即 -2147024864),这是最常见且稳定的标识ex.Message.Contains("used by another process") || ex.Message.Contains("正由另一进程使用")ex.InnerException 判断——它常为 null,且无额外信息File.Open 或 File.ReadAllText 做检测?这些高层封装方法默认使用 FileShare.Read,且内部会自动处理部分共享冲突(比如某些日志文件被记事本打开时,File.ReadAllText 仍可能成功)。它们返回的是“能否读取内容”,而非“能否按你的意图打开”。一旦你后续要用 FileMode.Create + FileAccess.Write 覆盖写入,前面的“读取成功”毫无参考价值。
真正需要的不是“能不能读”,而是“我接下来要怎么开,现在能不能开”。所以必须显式构造 FileStream,传入和业务逻辑完全一致的 FileMode、FileAccess、FileShare 参数:
try { using var _ = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None); // 模拟独占读 return false; // 未被独占}catch (IOException ex) when (IsFileLocked(ex)) { return true; // 被独占}
文件锁是瞬态资源:A 进程检测时没锁,刚释放 FileStream,B 进程就打开了它——这是典型的竞态条件(race condition)。检测只能降低失败概率,不能消除。生产环境应把检测当作“快速预检”,而非“绝对保障”。
关键做法:
try-catch,并重试逻辑(如延迟 100ms 后再试 2–3 次)Path.GetTempFileName() 避开竞争,而非死磕原文件Mutex)或文件锁约定,而不是反复试探真正难的不是写检测代码,而是接受“锁不可靠”这个事实,并在架构层面对它做防御性设计。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8