使用XmlTextWriter序列化然后使用XmlTextReader读取的XML文件有时会损坏

时间:2011-06-09 11:33:57

标签: c# xml

我们有一个产品在C# - .NET 2.0中使用'XmlTextWriter'来创建大量的小XML文件。然后使用'XmlTextReader'重复读取这些文件。

我们发现,在极少数情况下,在少数客户机器上,XML文件的内容被大量的空格所取代。一旦发生这种情况,“XmlTextReader”显然无法读取XML文件,并显示错误“Root Element is missing”。

以下是逻辑细节:

  1. 编写新的Xml文件时 - 首先使用以下命令将文件写入临时文件夹:

    XmlTextWriter xDoc = new XmlTextWriter(Path, Encoding.UTF8);
    
  2. 将文件写入临时文件夹后,“XmlTextReader”用于验证文件。

  3. 当且仅当文件经过验证后,才会将其复制到最终位置。

  4. 几天后,使用以下方法多次读取文件:

    XmlTextReader xDoc = new XmlTextReader(Path);
    
  5. 在极少数情况下,读者会因“Root Element is Missing”错误而失败,我们发现XML文件现在包含许多空格而没有XML数据。

  6. 以下是一些代码摘录:

    此代码用于序列化 (请记住,序列化是对临时文件夹完成的,只有在验证临时XmlFile后才会复制到最终位置。)

                public void SerializeWithXmlTextWriter(XMLMetaData instance, string Path)
        {
            instance.CommitLists();
    
            #region XmlTextWriter
    
            XmlTextWriter xDoc = null;
    
            try
            {
                xDoc = new XmlTextWriter(Path, Encoding.UTF8);
                xDoc.Formatting = Formatting.Indented;
    
                xDoc.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
                xDoc.WriteStartElement("MD");
                xDoc.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
                xDoc.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
    
    
    // A number of other elements are written here
    
                xDoc.WriteEndElement();
            }
            finally
            {
                if (xDoc != null)
                {
                    xDoc.Close();
                    xDoc = null;
                }
            }
    
            #endregion
        }
    

    此代码用于反序列化 (它还用于在序列化后验证文件。)

                public XMLMetaData DeserializeWithXmlTextReader(string Path)
        {
            XMLMetaData instance = new XMLMetaData();
    
            #region XmlTextReader
    
            XmlTextReader xDoc = null;
    
            try
            {
                xDoc = new XmlTextReader(Path);
    
    
    
                while (xDoc.Read())
                {
                    switch (xDoc.Name)
                    {
                        //Each element is processed using a case statement
                        //Omitted from this code sample
                    }
                }
            }
            finally
            {
                if (xDoc != null)
                {
                    xDoc.Close();
                    xDoc = null;
                }
            }
    
            #endregion
    
            return instance;
        }
    

    我们一直试图解决这个问题好几个月而且无法到达任何地方,因为它只发生在成千上万的客户端机器上。我们从来没有能够在我们的开发和测试机器上复制它。

    我们已经有过停止备份应用程序时问题消失的报告。我们还有一位客户在运行Visual Studio时似乎只有问题。

    对于有此问题的客户 - 它似乎每隔几周就会发生一次!

    提前感谢您的帮助:)

    西蒙

3 个答案:

答案 0 :(得分:1)

至少自从我们切换到.Net 2.0以来,我们遇到了同样的问题。

我们使用'XmlTextWriter'和ISO-8859-1编码写入临时文件,然后将其复制。 我们得到一个空文件,大小为0。

我们在关闭前使用Flush但这也不起作用。

这种情况很少发生,我们有大约4000名用户,大约每月发生一次。假设存在一个内部错误,它没有例外。

我们使用该文件进行设置,因此我们当前的解决方法是在读取时遇到此问题时生成默认值。

我们也在使用Formatting.Indented,也许这就是罪魁祸首。

我们的代码:

    Public Sub Save(ByVal st As Stream, Optional ByVal AttachComment As Boolean = True)

    Dim xtw As New XmlTextWriter(st, Text.Encoding.GetEncoding("ISO-8859-1"))

    xtw.Formatting = Formatting.Indented

    xtw.WriteStartDocument()

    'Header.
    If AttachComment Then
        xtw.WriteComment(GenerateCreationComment())
    End If

    xtw.WriteStartElement("SektionsdataFile")

    xtw.WriteStartElement("Header")
    WriteStringElement(xtw, "FileType", "Settings")
    WriteStringElement(xtw, "FormatVersion", CurrentFormatVersion)
    xtw.WriteEndElement()

    'Settings.
    xtw.WriteStartElement("Settings")

    SaveSettingsCategory(xtw, Application)
    SaveSettingsCategory(xtw, Behaviour)
    SaveSettingsCategory(xtw, Calculation)
    SaveSettingsCategory(xtw, Forms)
    SaveSettingsCategory(xtw, Hardware)
    SaveSettingsCategory(xtw, Layout)
    SaveSettingsCategory(xtw, License)
    SaveSettingsCategory(xtw, Paths)
    SaveSettingsCategory(xtw, Printing)

    xtw.WriteEndElement()

    xtw.WriteEndElement()

    xtw.WriteEndDocument()

    xtw.Flush()

    xtw.Close()

End Sub

答案 1 :(得分:0)

您声明该文件已经过验证,然后被复制,并且验证后的文件会中断。我至少可以看到四种可能性:

  1. 比赛条件。出现此问题的原因是您在复制新版本的同时读取文件以替换它。
  2. 复制过程出了问题。
  3. 文件已成功复制,之后被其他一些过程消隐。
  4. 在您阅读配置时,文件已成功复制,之后被XmlTextReader中的错误消除。
  5. 1的解决方案是使用跨进程同步 - 例如信号量。

    要调查2,您可以在复制后检查文件。

    对于3和4的偏执,您可以确保副本以只读方式创建,对于4,您可以向XmlTextReader传递FileStream打开的只读而不是路径。

    如果这些都没有帮助,至少你会排除一些可能性。

答案 2 :(得分:0)

首先使用

using(XmlWriter xmlw = XmlWriter.Create(String, XmlWriterSettings))
{
  // your code here
}

作为创建xml文档的样板。尝试一下,如果失败也会回来(我会感到惊讶)。还可以使用using构造来读取XML。

XmlTextReader的使用是not recommended by Microsoft(参见注释)。