在C#中,如果2个进程正在读取和写入同一个文件,那么避免进程锁定exception的最佳方法是什么?

使用以下文件读取代码:

using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None)) { using (TextReader tr = new StreamReader(fileStream)) { string fileContents = tr.ReadToEnd(); } } 

并且以下文件编写代码:

 using (TextWriter tw = new StreamWriter(fileName)) { tw.Write(fileContents); tw.Close(); } 

可以看到以下exception详细信息:

该进程无法访问文件’c:\ temp \ myfile.txt’,因为它正由另一个进程使用。

避免这种情况的最佳方法是什么? 读者是否需要在收到例外后重试或者有更好的方法吗?

请注意,阅读器进程使用FileSystemWatcher来了解文件何时更改。

另请注意,在这种情况下,我不是在寻找在两个进程之间共享字符串的替代方法。

您可以打开文件进行写入,仅锁定写入权限,从而允许其他人仍然读取该文件。

例如,

 using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) { // Do your writing here. } 

其他文件访问只是打开文件进行读取而不是写入,并允许读写共享。

 using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { // Does reading here. } 

如果您想确保读者始终读取最新文件,您将需要使用一个锁定文件来指示某人正在写入该文件(尽管如果不仔细实施,您可能会遇到竞争条件)或者确保在打开读取和处理exception时阻止写入共享,因此您可以再次尝试直到获得独占访问权限。

如果创建了一个已命名的Mutex,则可以在编写应用程序中定义互斥锁,并让读取应用程序等到释放互斥锁。

因此,在当前使用FileSystemWatcher的通知过程中,只需检查是否需要等待互斥锁,如果这样做,它将等待,然后进行处理。

这是我发现的一个像这样的Mutex的VB示例 ,它应该很容易转换为C#。

使用FileShare.None打开文件有什么特别的原因吗? 这将阻止任何其他进程打开该文件。

FileShare.Write或FileShare.ReadWrite应该允许其他进程(受权限限制)在您阅读时打开并写入文件,但是当您阅读文件时,您必须注意文件在您下面的变化 – 只需缓冲开放时的内容可能会有所帮助。

但是,所有这些答案都同样有效 – 最佳解决方案取决于您正在尝试对文件执行的操作:如果在保证不更改的同时读取它很重要,则将其锁定并处理后续exception在你的写作代码中; 如果同时读取和写入它很重要,则更改FileShare常量。

您可以使用Mutex对象。

如果正在写入文件,请让您的进程检查文件的状态。 您可以通过存在锁定文件来执行此操作(即,此其他文件的存在,可以为空,防止写入主文件)。

但是,即使这不是故障保护,因为这两个进程可能同时创建锁定文件 – 但您可以在提交写入之前检查这一点。

如果您的进程遇到锁定文件,则让它只是hibernate/等待,并在将来以预定义的时间间隔再次尝试。

读者和作者都需要重试机制。 此外, FileShare应设置为FileShare.read为读者, FileShare.none为writer。 这应确保读者在写入过程中不读取文件。

读者(不包括重试)成为

 using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (TextReader tr = new StreamReader(fileStream)) { string fileContents = tr.ReadToEnd(); } } 

作者(不包括重试)成为:

 FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None); using (TextWriter tw = new StreamWriter(fileStream)) { tw.Write(fileContents); tw.Close(); } 

写入临时文件,完成重命名/将文件移动到读者正在寻找的位置和/或名称。

最好的办法是将应用程序协议放在文件传输/所有权转移机制之上。 “锁定文件”机制是一个古老的UNIX黑客攻击已经存在了很长时间。 最好的办法就是将文件“交给”读者。 有很多方法可以做到这一点。 您可以使用随机文件名创建文件,然后将“名称”提供给阅读器。 这将允许编写器异步写入另一个文件。 想想“网页”的工作原理。 对于图像,脚本,外部内容等,网页上有更多信息的“链接”。服务器会向您发送该页面,因为它是您想要的“资源”的连贯视图。 然后,您的浏览器将根据页面描述(HTML文件或其他返回的内容)获取相应的内容,然后传输所需内容。

这是最具弹性的“共享”机制。 编写文件,共享名称,移动到下一个文件。 “共享名称”部分是primefaces性的手段,确保双方(读者和作者)同意内容是“完整的”。