FileStream 共享陷阱:为什么设置了 FileShare.Read 依然报错?
2025-11-21 20:50:28
#为什么明明允许“共享读”,却还是被锁了?
最近在写一段 C# 文件处理逻辑时,我掉进了一个看似简单却颇具迷惑性的坑。需求很简单:一个线程在写日志,另一个线程想要实时读取。
我理所当然地写下了这段代码:
#案发现场与解决方法
1 | string fileName = "test.txt"; |
这看起来很不合理,对吧?fs1 说“我允许别人读”,fs2 说“我要读”。明明两情相悦,为什么系统报了 IOException?
根本原因解析:
问题的关键在于 fs2 构造函数中的 FileShare.Read 参数。
FileAccess是我想做什么。FileShare是我允许别人(也就是文件上已存在的其他句柄)做什么。
当 fs2 尝试打开文件时,操作系统会进行双向检查:
fs2请求FileAccess.Read。检查fs1的共享设置:fs1声明了FileShare.Read。通过。fs2声明了FileShare.Read。这意味着fs2告诉操作系统:“在这个文件上,我只允许别人进行读操作”。检查fs1的当前权限:fs1正在持有FileAccess.Write。
冲突爆发: fs2 的共享策略(只许读,不许写)与 fs1 正在做的事情(写)发生了冲突。因此,Windows 拒绝了 fs2 的请求。
解决方法:
fs2 必须显式地宽容 fs1 的写入行为。我们需要将 fs2 的共享模式改为 ReadWrite:
1 | // 修正后的代码:fs2 必须允许其他人“Write”,因为 fs1 确实正在 Write |
#底层真相:这是 Windows 的锅 (Win32 API 复现)
有人可能会怀疑这是 .NET 框架本身设计的“矫情”。为了自证清白,我直接使用 C++ 调用 Win32 API CreateFile 来复现这个场景。你会发现,结果一模一样。
在 Windows 内核中,文件共享机制是非常严格的。
FileAccess.Write对应GENERIC_WRITEFileShare.Read对应FILE_SHARE_READ
下面是 C++ 的复现代码:
1 |
|
#总结
不要被 FileShare 的名字误导,以为它只是“我开放给别人的权限”。在第二次打开文件时,它实际上变成了一个过滤器:它必须兼容文件上当前已存在的所有句柄的权限。
如果你的程序中有个 Writer 正在工作,任何后来的 Reader 想要加入,都必须在自己的 FileShare 中显式包含 Write,承认 Writer 的存在。