XmlDocument garbled when opening and saving via StreamReader/StreamWriter

I have a WinForms application in C# that uses XML configuration files.

To prevent other apps and users to edit those files while the app is running I use...

To open document:

document = new XmlDocument();

using ( var xr = new StreamReader( new FileStream( fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read ), Encoding.UTF8 ) )
{
    document.Load( xr );
}

...a Save() method that uses the writer to save the file again.

lock ( syncLock )
{
    using ( var writer = XmlTextWriter.Create( new FileStream( fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read ), settings ) )
    {
        document.Save( writer );
    }
}

The lock is there since multiple threads may want to save to the file. I'm actually not sure if that is making any sense at this end.

When I, for isntance, remove a node from the DOM tree and then save the file, the file becomes garbage.

This nice file...

<?xml version="1.0" encoding="utf-8"?>
<history>
  <period something="2013-01-01 04:55:12" added="2013-01-01 04:58:12" />
  <period something="2013-01-01 10:55:12" added="2013-01-01 10:58:12" />
  <period something="2013-01-01 16:55:12" added="2013-01-01 16:58:12" />
  <period something="2013-01-01 22:55:12" added="2013-01-01 22:58:12" />
  <period something="2013-01-02 04:55:12" added="2013-01-02 04:58:12" />
  <period something="2013-01-02 10:55:12" added="2013-01-02 10:58:12" />
  <period something="2013-01-02 16:55:12" added="2013-01-02 16:58:12" />
  <period something="2013-01-02 22:55:12" added="2013-01-02 22:58:12" />
</history>

...becomes this:

<?xml version="1.0" encoding="utf-8"?>
<history>
  <period something="2013-01-01 04:55:12" added="2013-01-01 04:58:12" />
  <period something="2013-01-01 10:55:12" added="2013-01-01 10:58:12" />
  <period something="2013-01-01 16:55:12" added="2013-01-01 16:58:12" />
  <period something="2013-01-01 22:55:12" added="2013-01-01 22:58:12" />
  <period something="2013-01-02 04:55:12" added="2013-01-02 04:58:12" />
  <period something="2013-01-02 10:55:12" added="2013-01-02 10:58:12" />
  <period something="2013-01-02 16:55:12" added="2013-01-02 16:58:12" />
</history>/>
    <period something="2013-01-02 22:55:12" added="2013-01-02 22:58:12" />
</history>

So the node I deleted is back, but the document is no longer well formed.

Why? Any idea?

Jon Skeet
people
quotationmark

This is the problem:

new FileStream( fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite )

If the file already exists, that will overwrite the existing file, but will not truncate it.

You should specify FileMode.Create... or more simply, just use File.Create to obtain the stream. Even better, don't bother with StreamWriter or StreamReaer, or even manually creating the stream. Heck, when loading the file you can just specify the filename:

document = new XmlDocument();
document.Load(fileName);

And for saving, if you really need the custom settings:

using (var writer = XmlWriter.Create(fileName, settings))
{
    document.Save(writer);
}    

I would strongly suggest that you prevent reading from the file while you're writing it, by the way - while it's being written, it won't be a valid XML file anyway.

I'd also encourage you to migrate from XmlDocument to LINQ to XML (XDocument etc) if you possibly can - it's a much nicer API.

people

See more on this question at Stackoverflow