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

时间:2022-08-21 22:46:16

With the following file reading code:

使用以下文件读取代码:

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

And the following file write code:

并且以下文件编写代码:

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

The following exception details are seen:

可以看到以下异常详细信息:

The process cannot access the file 'c:\temp\myfile.txt' because it is being used by another process.

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

What is the best way of avoiding this? Does the reader need to retry upon receipt of the exception or is there some better way?

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

Note that the reader process is using a FileSystemWatcher to know when the file has changed.

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

Also note that, in this instance, I'm not looking for alternatives ways of sharing strings between the 2 processes.

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

8 个解决方案

#1


34  

You can open a file for writing and only lock write access, thereby allowing others to still read the file.

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

For example,

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

Other file access just opens the file for reading and not writing, and allows readwrite sharing.

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

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

If you want to ensure that readers will always read an up-to-date file, you will either need to use a locking file that indicates someone is writing to the file (though you may get a race condition if not carefully implemented) or make sure you block write-sharing when opening to read and handle the exception so you can try again until you get exclusive access.

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

#2


6  

If you create a named Mutex you can define the mutex in the writing application, and have the reading application wait until the mutex is released.

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

So in the notification process that is currently working with the FileSystemWatcher, simply check to see if you need to wait for the mutex, if you do, it will wait, then process.

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

Here is a VB example of a Mutex like this that I found, it should be easy enough to convert to C#.

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

#3


3  

Is there any particular reason for opening the file with FileShare.None? That'll prevent the file from being opened by any other process.

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

FileShare.Write or FileShare.ReadWrite should allow the other process (subject to permissions) to open and write to the file while you are reading it, however you'll have to watch for the file changing underneath you while you read it - simply buffering the contents upon opening may help here.

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

All of these answers, however, are equally valid - the best solution depends on exactly what you're trying to do with the file: if it's important to read it while guaranteeing it doesn't change, then lock it and handle the subsequent exception in your writing code; if it's important to read and write to it at the same time, then change the FileShare constant.

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

#4


2  

You can use a Mutex object for this.

您可以使用Mutex对象。

#5


2  

Get your process to check the status of the file if it is being written to. You can do this by the presence of a lock file (i.e. the presence of this other file, which can be empty, prevents writing to the main file).

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

Even this is not failsafe however, as the two processes may create the lock file at the same time - but you can check for this before you commit the write.

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

If your process encounters a lock file then get it to simply sleep/wait and try again at a predefined interval in the future.

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

#6


2  

The reader and writer both need retry mechanisms. Also FileShare should be set to FileShare.read for the readers and FileShare.none for the writer. This should ensure that the readers don't read the file while writing is in progress.

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

The reader (excluding retry) becomes

读者(不包括重试)成为

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

The writer (excluding retry) becomes:

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

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

#7


1  

Write to a temp file, when finished writing rename/move the file to the location and/or name that the reader is looking for.

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

#8


1  

The best thing to do, is to put an application protocol on top of a file transfer/ownership transfer mechanism. The "lock-file" mechanism is an old UNIX hack that has been around for ages. The best thing to do, is to just "hand" the file over to the reader. There are lots of ways to do this. You can create the file with a random file name, and then "give" that name to the reader. That would allow the writer to asynchronously write another file. Think of how the "web page" works. A web page has a "link" to more information in it, for images, scripts, external content etc. The server hands you that page, because it's a coherent view of the "resource" you want. Your browser then goes and gets the appropriate content, based on what the page description (the HTML file or other returned content), and then transfers what it needs.

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

This is the most resilient type of "sharing" mechanism to use. Write the file, share the name, move to the next file. The "sharing the name" part, is the atomic hand off that makes sure that both parties (the reader and the writer) agree that the content is "complete."

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

#1


34  

You can open a file for writing and only lock write access, thereby allowing others to still read the file.

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

For example,

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

Other file access just opens the file for reading and not writing, and allows readwrite sharing.

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

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

If you want to ensure that readers will always read an up-to-date file, you will either need to use a locking file that indicates someone is writing to the file (though you may get a race condition if not carefully implemented) or make sure you block write-sharing when opening to read and handle the exception so you can try again until you get exclusive access.

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

#2


6  

If you create a named Mutex you can define the mutex in the writing application, and have the reading application wait until the mutex is released.

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

So in the notification process that is currently working with the FileSystemWatcher, simply check to see if you need to wait for the mutex, if you do, it will wait, then process.

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

Here is a VB example of a Mutex like this that I found, it should be easy enough to convert to C#.

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

#3


3  

Is there any particular reason for opening the file with FileShare.None? That'll prevent the file from being opened by any other process.

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

FileShare.Write or FileShare.ReadWrite should allow the other process (subject to permissions) to open and write to the file while you are reading it, however you'll have to watch for the file changing underneath you while you read it - simply buffering the contents upon opening may help here.

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

All of these answers, however, are equally valid - the best solution depends on exactly what you're trying to do with the file: if it's important to read it while guaranteeing it doesn't change, then lock it and handle the subsequent exception in your writing code; if it's important to read and write to it at the same time, then change the FileShare constant.

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

#4


2  

You can use a Mutex object for this.

您可以使用Mutex对象。

#5


2  

Get your process to check the status of the file if it is being written to. You can do this by the presence of a lock file (i.e. the presence of this other file, which can be empty, prevents writing to the main file).

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

Even this is not failsafe however, as the two processes may create the lock file at the same time - but you can check for this before you commit the write.

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

If your process encounters a lock file then get it to simply sleep/wait and try again at a predefined interval in the future.

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

#6


2  

The reader and writer both need retry mechanisms. Also FileShare should be set to FileShare.read for the readers and FileShare.none for the writer. This should ensure that the readers don't read the file while writing is in progress.

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

The reader (excluding retry) becomes

读者(不包括重试)成为

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

The writer (excluding retry) becomes:

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

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

#7


1  

Write to a temp file, when finished writing rename/move the file to the location and/or name that the reader is looking for.

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

#8


1  

The best thing to do, is to put an application protocol on top of a file transfer/ownership transfer mechanism. The "lock-file" mechanism is an old UNIX hack that has been around for ages. The best thing to do, is to just "hand" the file over to the reader. There are lots of ways to do this. You can create the file with a random file name, and then "give" that name to the reader. That would allow the writer to asynchronously write another file. Think of how the "web page" works. A web page has a "link" to more information in it, for images, scripts, external content etc. The server hands you that page, because it's a coherent view of the "resource" you want. Your browser then goes and gets the appropriate content, based on what the page description (the HTML file or other returned content), and then transfers what it needs.

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

This is the most resilient type of "sharing" mechanism to use. Write the file, share the name, move to the next file. The "sharing the name" part, is the atomic hand off that makes sure that both parties (the reader and the writer) agree that the content is "complete."

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