• 关于C# XML序列化的一个BUG的修改


    关于C# XML序列化的一个BUG的修改

    在我前一篇博客中提到用XML序列化作为数据库的一个方案,@拿笔小心 提到他们在用XML序列化时,遇到了一个比较严重的bug,即XML不闭合,系统不能正确的加载此XML。在我的开发经验中,也遇到过这样的问题。现在把这个BUG的描述及解决方案记录如下,也供遇到此BUG的朋友参考。

    BUG描述

    这个BUG的出现也是比较诡异的,我们给客户做的一套系统,这个系统会把数据写到N个xml文件中,正常情况下都没有问题。直到有一天……客户运行程序运行了一天,到快下班的时候,把数据保存到数据库中;第二天来上班时,忽然发现数据都没有了,也就是说昨天一天的工作白做了。

    当客户把这个BUG告诉我的时候,我第一时间的反应是要重现这个BUG。因为同样的系统N份已经运行了一年了,从来没有出现过这个问题。结果客户在同样的机器上再次测试,没有遇到这个问题。我以为这个BUG是偶然现象,就没有处理,结果噩梦开始了。

    当客户把系统部署到生产系统中之后,生产系统中偶尔也出现这个问题,每次出现这个问题,基本上耽误了一天的工作,损失都是N万,当时压力巨大,赶紧扎到现场解决问题。

    我发现之所以以前没有出现这个BUG,是因为以前的数据量都非常少,但这个版本的数据量很大。我观察了数据文件,发现是XML文件丢失了一部分结尾造成的。如丢失一个>号,导致不能正确加载XML,数据丢失。

    解决方案1

    既然定位到了问题,那就有解决方案了。每次写完数据之后,我都会重新LOAD一下数据以验证正确性,如果不正确,则重新写入数据。用这个思路,我很快改了一版,部署到生产环境中。(测试环境很难重新这个错误)。

    然而,问题还是没有解决,一个月之后,同样的问题又出现了。看来必须找到根本原因,不能取巧解决问题。

    解决方案2

    我开始google这个问题,最后在stackoverflow上找到:xdocument save adding extra characters。他的描述是XML会增加字符,我的问题是会减少字符。

    原来XML的写入方式是:

    config.Save(new FileStream(@"c:foo.xml", FileMode.Create, FileAccess.Write), SaveOptions.None);
    

    应该改为

    using (FileStream fs = new FileStream(@"C:foo.xml", FileMode.Truncate, FileAccess.Read))
    {
        config.Load(fs);
    }
    

    主要修改是把FileMode.Create改为FileMode.Truncate。

    Use FileMode.Truncate in your write FileStream so that the file is truncated to 0 bytes before you start writing to it.

    这个方案看起来是靠谱的,然而,我还是不放心。

    解决方案3

    为了防止再次出问题,我写了一个FixErrorXmlFile方法,解决去除xml多字符的问题,在每次加载xml的时候,如果出现错误,调用此方法修正xml错误。其核心代码如下:

      private static bool ReadFile(string filePath, out string realContent)
            {
                string content = string.Empty;
                realContent = string.Empty;
                using (FileStream fs = new FileStream(filePath, FileMode.Truncate))
                {
                    using (StreamReader sr = new StreamReader(fs))
                    {
                        content = sr.ReadToEnd();
                    }
                }
                //首先,要找到文件头末尾的'>'(即第一个右尖括号)的索引值index1,如果index1的值小于1,说明'>'不存在,跳出:否则往下执行
                //然后,找到根元素左侧的'<'的索引值index2,同样,如果'<'存在继续往下执行
                //      找到根元素右侧的第一个'>'的索引值index3和第一个' '的索引值index4
                //      比较index3和index4,较小者为根元素右侧的第一个元素的索引
                //      找出根元素的名称
                //接着,找到最后一个匹配根元素名称的开始位置index5
                //最后,确定根元素右侧第一个'>'的索引值,来获取文件的真正内容realContent
                int index1 = content.IndexOf('>');
                if (index1 < 1)
                {
                    return false;
                }
                int index2 = content.IndexOf("<", index1);
                if (index2 < 1)
                {
                    return false;
                }
                int index3 = content.IndexOf(">", index2);
                int index4 = content.IndexOf(" ", index2);
                int index = index3 < index4 ? index3 : index4;
                string rootName = content.Substring(index2 + 1, index - index2 - 1);
                int index5 = content.LastIndexOf(rootName);
                if (index5 < 1)
                {
                    return false;
                }
                index5 += rootName.Length;
                realContent = content.Substring(0, index5 + 1);
                return true;
            }
    

    后记

    我同时把解决方案2和解决方案3都修改了,再次放到了生产系统中。一年过去了,再也没有出现过这个BUG。这个一年指的是同时5台机器一直不停的运行。

    后来我又观察了一下,好像我的解决方案3根本就没起作用,从来没有进入过这个函数。也就是说,解决方案2已经解决了这个问题。

    虽然这个问题没有重现,但我还是不认为这个问题已经完美解决。我认为这是微软的一个BUG,在正常应用序列化的情况下会出现丢失数据,应该由微软来解决,而不是采用其它的补丁方式解决问题。微软类似的BUG遇到好几个了。

    总之,这个问题就是这样解决了,希望对遇到相似问题的人有所帮助。也欢迎大家指出我的问题。

    参考:

    http://www.cnblogs.com/wardensky/p/4170605.html

    我同事当时记录的这个问题:xml存储bug

  • 相关阅读:
    Ubuntu 14.04 卸载通过源码安装的库
    Ubuntu 14.04 indigo 相关依赖
    Ubuntu 14.04 indigo 安装 cartographer 1.0.0
    Ubuntu 14.04 改变文件或者文件夹的拥有者
    安装cartographer遇到Unrecognized syntax identifier "proto3". This parser only recognizes "proto2"问题
    Unrecognized syntax identifier "proto3". This parser only recognizes "proto2". ”问题解决方法
    查看所有用户组,用户名
    1卸载ROS
    Ubuntu14.04 软件安装卸载
    Ubuntu14.04系统显示器不自动休眠修改
  • 原文地址:https://www.cnblogs.com/wardensky/p/4172970.html
Copyright © 2020-2023  润新知