.NET Core如何检查网络共享中的文件是否未被占用
1. 能否用File.Open方法检查网络共享文件是否未被占用?
你的代码没达到预期,核心原因是用了FileShare.ReadWrite参数——这个参数允许其他进程同时对文件进行读/写操作,哪怕文件正被写入,只要写入方设置了兼容的共享模式,你的File.Open就会成功打开,自然返回true。
退一步说,就算调整共享参数,网络共享场景下这种方式也不可靠:一是不同操作系统的文件锁机制在SMB这类网络协议下表现不一致;二是存在竞态条件——你刚检查完文件“可用”,准备复制的瞬间,写入方可能又开始写入,最终还是拿到不完整的文件。
2. 仅检查文件大小是否可行?
不可行。写入大文件时,可能因缓存机制导致文件大小不会实时增长(比如写入方先写内存缓存,隔一段时间才刷到磁盘),这时你看到的大小暂时不变,会误以为文件已写完;另外如果写入方分批次写入、中间有停顿,也会出现同样的误判。而且网络共享中获取文件大小可能存在延迟,进一步增加误判概率。
3. 这类场景的最佳实践
方案一:原子性文件重命名(最推荐)
写入方先将文件写入为临时文件名(比如data.tmp),当整个文件完全写入完成后,再将临时文件重命名为正式文件名(比如data.csv)。文件系统的重命名操作是原子性的,处理方只需要扫描目录中正式文件名的文件,直接复制即可——只要正式文件名存在,就说明文件已经写入完成,完全不需要额外检查。
方案二:创建标记文件
写入方完成文件写入后,在同一目录下创建对应的标记文件(比如写完data.csv后,创建data.csv.finished)。处理方扫描目录时,只有同时找到主文件和对应的标记文件,才开始复制;复制完成后可删除标记文件,避免重复处理。
方案三:进程间直接通知(若两个应用均可控)
如果写入应用和处理应用都是你开发的,完全可以跳过文件系统的检查逻辑,用进程间通信(比如TCP消息、命名管道、本地数据库记录)直接通知——写入方每写完一个文件,就给处理方发消息,处理方直接处理指定文件,效率最高也最可靠。
方案四:FileSystemWatcher配合原子操作
用FileSystemWatcher监听目录的文件创建/重命名事件,结合原子重命名方案,当监听到正式文件名的文件被创建时,直接触发处理逻辑,避免轮询扫描目录的开销。
内容的提问来源于stack exchange,提问作者aik

