I have an application which works with XML file formats. The application can make changes to these XML files, but it also uses the System.IO.FileSystemWatcher to see if the XML files have changed outside of the program while the program was running. If the files have changed, then the application re-loads the XML files.
Of course, if the application saves the XML file, it causes Windows to detect that the file has changed, which kicks off the FileSystemWatcher events. I don't want the file to reload the XML files because of changes it has initiated, so whenever it saves a XML file, it keeps a count of the number of times to ignore when a particular file changes. Saving the XML file in the app increases the count. Reacting to a change on the file decreases the count if nonzero, or processes the change if the count is already 0.
The problem I'm encountering is that when I save the XML file, I do it as follows:
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);
}
...
Then I serialize my XML object to the stream using an XmlWriter then close the stream. All works fine except this causes my events in FileSystemWatcher to be raised twice. I've spent some time debugging and I've found that calling System.IO.File.Open with the Truncate option actually changes the file on disk. I've hit a breakpoint right after calling that and found the XML file is on disk with a size of 0 bytes. Therefore, it seems like this approach hits the disk twice, causing my FileSystemWatcher events to be raised twice.
How can I solve this problem?
As a workaround I've found that I can delete the file if it exists, then do a simple File.Open without the Truncate option and in my case that solves it...at least so far. I'm assuming this would kick of a Delete event on the FileSystemWatcher. Technically I don't want to delete the file, and if I were to add specific logic to when a file is deleted at a later time, this code would probably cause that to fire improperly.
Any other ways to change an existing file without causing 2 FileSystemWatcher events?
Update 1
It's been many years since I've asked this question and the file watch system has become a central part of an app I've been working with and maintaining ever since I originally asked the question over 5 years ago.
Unfortunately since that time I still haven't found a better solution to serliaizing XML to disk without causing 2 file watch changes.
For future readers here's the code I'm using:
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);
}
}