2017-10-13 112 views
0

我用下面的代码来存储在磁盘上的一些对象:DataContractSerializer的写入损坏的数据

public static void Save<T>(T obj, string filename) 
    { 
     using (var output = System.IO.File.OpenWrite(filename)) 
     using (var writer = new System.Xml.XmlTextWriter(output, System.Text.Encoding.UTF8) 
     { 
      Formatting = System.Xml.Formatting.Indented 
     }) 
     { 
      var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(T)); 
      serializer.WriteObject(writer, obj); 
     } 
    } 

有时保存的文件被损坏,这意味着它由防止进一步的反序列化一些随机附加的垃圾数据,例如这样的事情:

<Parameters xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyApp"> 
    ... 
</Parameters>eters> 

这里最后6个字符来自一些遗迹的标签和反序列化,从这个文件阻止。为什么会发生,我该如何解决?

是否可以通过调用Form.Closing事件处理程序中的Save方法引起?

+1

有点看起来像你正在重复写入同一个文件,并且在你再次写入文件之前文件没有被截断。如果你上次写给它的内容长了六个字符,并且以“'''”结尾,就像新的一样 - 你就是这样。 'System.IO.File.Delete(filename);'作为方法的第一行应该清除,我想。不知道是否在文件不存在时抛出。 –

+0

@EdPlunkett当然!从OpenWrite的文档:“打开一个现有的文件或创建一个新的文件写入。”非常感谢你! – Szybki

+3

使用'new System.IO.FileStream(filename,FileMode.Create)'而不是'OpenWrite'。 –

回答

1

这是documented behavior with OpenWrite()

的OpenWrite方法打开一个文件,如果一个已经存在的文件路径,或创建一个新的文件,如果一个不存在。对于现有文件,它不会将新文本附加到现有文本。相反,它会用新字符覆盖现有字符。 如果您用较短的字符串(如“第二次运行”),覆盖较长的字符串(例如“这是对OpenWrite方法的测试”),该文件将包含字符串(“ OpenWrite方法的第二次运行测试“)。

因此,您需要在写入之前明确地截断文件,或者如果存在,就删除它。

亚历山大·彼得罗夫指出new System.IO.FileStream(filename, FileMode.Create)OpenWrite()在这种情况下,正确的替换。