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?
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.
See more on this question at Stackoverflow