如何防止System.IO.File.Open使用FileMode.截断导致文件更改的部分
本文关键字:文件 IO System 何防止 File Open FileMode 使用 | 更新日期: 2023-09-27 18:18:08
我有一个使用XML文件格式的应用程序。应用程序可以对这些XML文件进行更改,但它也使用System.IO.FileSystemWatcher来查看在程序运行时XML文件是否在程序之外发生了更改。如果文件已经更改,那么应用程序将重新加载XML文件。
当然,如果应用程序保存XML文件,它会导致Windows检测到文件已更改,从而启动FileSystemWatcher事件。我不希望该文件因为发起了更改而重新加载XML文件,因此每当保存XML文件时,它都会记录在特定文件更改时要忽略的次数。在应用程序中保存XML文件会增加计数。
我遇到的问题是,当我保存XML文件时,我这样做:
Stream fileStream = null;
if(System.IO.File.Exists(fileToSave)
{
fileStream = System.IO.File.Open(fileName, FileMode.OpenOrCreate | FileMode.Truncate);
}
else
{
fs = System.IO.File.Open(fileName, FileMode.OpenOrCreate);
}
...
然后我使用XmlWriter将我的XML对象序列化到流,然后关闭流。所有工作都很好,只是这会导致我在FileSystemWatcher中的事件被引发两次。我花了一些时间调试,发现用Truncate选项调用System.IO.File.Open实际上改变了磁盘上的文件。在调用它之后,我遇到了一个断点,发现XML文件在磁盘上,大小为0字节。因此,这种方法似乎击中磁盘两次,导致我的FileSystemWatcher事件被触发两次。
我该如何解决这个问题?
作为一个解决方案,我发现我可以删除文件,如果它存在,然后做一个简单的文件。打开没有截断选项,在我的情况下,解决它…至少目前是这样。我假设这会在FileSystemWatcher上触发一个Delete事件。从技术上讲,我不想删除文件,如果我在以后删除文件时添加特定的逻辑,那么这段代码可能会导致不正确地触发。
还有其他方法可以改变现有的文件而不引起2 FileSystemWatcher事件吗?
更新1
我问这个问题已经很多年了,自从5年前我第一次问这个问题以来,文件监视系统已经成为我一直在使用和维护的一个应用程序的核心部分。
不幸的是,从那时起,我仍然没有找到一个更好的解决方案来序列化XML到磁盘而不引起2个文件监视更改。
对于将来的读者,这里是我使用的代码:
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
using( var fs = System.IO.File.Open(fileName, FileMode.OpenOrCreate))
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using(var writer = XmlWriter.Create(fs, settings))
{
// for info on this, see
// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
XmlSerializer serializer = XmlSerializer.FromTypes(new[] { type })[0];
serializer.Serialize(writer, objectToSerialize);
}
}
因此,您面临的情况是,目录中可能发生更改,您希望程序对这些更改作出反应。这本身不是问题。问题是,您的程序无法判断哪个进程正在进行更改。所以如果it改变了目录中的内容,那么你就会进入一个无限循环。
你想出的任何解决这个问题的方案都将是脆弱的,因为它会受到竞争条件的影响。您可以尝试设计一种方案,使您可以忽略您更改的文件的下N个更新通知,但在某些时候,您会发现某些其他进程进行了您忽略的更新。
唯一可靠的方法是有两个目录。您有一个submissions
目录,用于客户端程序添加文件。您的程序监视该目录中的添加。当客户端将文件添加到submissions
时,您的程序将该文件移动到repository
目录。客户端对repository
目录具有只读访问权限。只有您的程序可以添加、修改或删除存储库中的文件。
我不会实现任何逻辑来避免在某些情况下读取Xml文件。这样你的程序就容易多了。只要处理你的程序读取它自己所做的更改的情况,你就可以减少由于一种"忽略你自己的更改的神奇机制"而错过某些更改的可能性。