在 C# 中,如果 2 个进程正在读取和写入同一个文件,那么避免进程锁定异常的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/222089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C#, if 2 processes are reading and writing to the same file, what is the best way to avoid process locking exceptions?
提问by Iain
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 FileSystemWatcherto know when the file has changed.
请注意,读取器进程使用FileSystemWatcher来了解文件何时发生更改。
Also note that, in this instance, I'm notlooking for alternatives ways of sharing strings between the 2 processes.
另请注意,在这种情况下,我不是在寻找在 2 个进程之间共享字符串的替代方法。
采纳答案by Jeff Yates
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.
如果您想确保读者始终读取最新文件,您将需要使用锁定文件来指示有人正在写入文件(尽管如果不小心实施,您可能会遇到竞争条件)或确保在打开以读取和处理异常时阻止写共享,以便您可以重试,直到获得独占访问权限。
回答by leppie
You can use a Mutex
object for this.
您可以Mutex
为此使用一个对象。
回答by Mitchel Sellers
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.
如果您创建了一个命名的互斥锁,您可以在写入应用程序中定义互斥锁,并让读取应用程序等待互斥锁被释放。
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 Mutexlike this that I found, it should be easy enough to convert to C#.
回答by Anthony
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.
如果您的进程遇到锁定文件,则让它简单地休眠/等待,并在将来以预定义的时间间隔重试。
回答by KristoferA
Write to a temp file, when finished writing rename/move the file to the location and/or name that the reader is looking for.
写入临时文件,完成写入后,将文件重命名/移动到读取器正在查找的位置和/或名称。
回答by symonc
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 常量。
回答by Iain
The reader and writer both need retry mechanisms. Also FileShareshould be set to FileShare.readfor the readers and FileShare.nonefor the writer. This should ensure that the readers don't read the file while writing is in progress.
读写器都需要重试机制。此外,FileShare应设置为FileShare.read为读者和FileShare.none为作者。这应该确保读者在写入过程中不会读取文件。
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();
}
回答by grwww
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 黑客,已经存在多年。最好的办法是将文件“交给”读者。有很多方法可以做到这一点。您可以使用随机文件名创建文件,然后将该名称“提供”给阅读器。这将允许作者异步写入另一个文件。想想“网页”是如何工作的。一个网页有一个指向更多信息的“链接”,包括图像、脚本、外部内容等。服务器将那个页面交给你,因为它是你想要的“资源”的连贯视图。然后你的浏览器会去获取适当的内容,
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."
这是最具弹性的“共享”机制类型。写入文件,共享名称,移至下一个文件。“共享名称”部分是确保双方(读者和作者)同意内容“完整”的原子切换。