Sometimes the xml file contents disappear in C#

It is very weird.

My Program call the following method almost every 10 seconds.

public void System_Save_Xml(string SystemPath)
    {
        XmlDocument doc = new XmlDocument();
        XmlElement xmlSystem = doc.CreateElement("System");

        XmlElement el_Option = doc.CreateElement("Option");
        el_Option.InnerText = Option;
        xmlSystem.AppendChild(el_Option);

        doc.AppendChild(xmlSystem);
        doc.Save(SystemPath);
    }
 public void System_Load_Xml(string SystemPath)
    {
        if (System.IO.File.Exists(SystemPath) == false) return;            

        XmlDocument doc = new XmlDocument();
        doc.Load(SystemPath);

        XmlNode el_Option = doc.SelectSingleNode("//System/Option");
        if (el_Port_LightCtr != null)
        {
            Option = el_Option.InnerText;
        }
    }

This works well. But sometimes, very occasionally, the content of the xml file disappears. Xml file is exits but file has no content. just empty. So the xml file load fails and an exception is thrown. -xml root element not found. I tried to print a message when it failed, but I couldn't catch.

Are there people who experienced the same symptoms as me? Or can you guess what the problem is?


My guess at the problem is that XmlDocument.Save does not work transactionally.

If the xml file already exists before System_Save_Xml runs, there will be a small period during the call where the file will be half-written.

Code reading the file at this time will not see the valid document that existed before, or the new updated document, but an invalid one.

In the cases I've seen it will have a bunch of 0 bytes written to the file. You should be able to use a try-catch around doc.Load to capture the exact error message you are getting and (with a bit more work) find the state that the file is in to cause it.

If my guess is right, its a kind of race condition that you can solve with:

  • A lock in your code so that the file isn't loaded while Save is executing (e.g. if you have no other code that's potentially reading during the Save call)
  • An exclusive file system lock on the save process (do the save yourself with a stream and XmlWriter)
  • Save new data to a temporary "update" file and use File.Replace to update the main file