首页新闻找找看学习计划

c# 如何操作写入巨型xml文件,大概有1GB的样子,写入操作很频繁,一定要使用xml。

0
悬赏园豆:50 [已解决问题] 解决于 2013-07-26 15:11

c# 如何操作写入巨型xml文件,大概有1GB的样子,写入操作很频繁,一定要使用xml。

如何能不一次性把整个文件加载进去,而是加载一个指针类的东西,部分写入。

沧海一杰的主页 沧海一杰 | 初学一级 | 园豆:28
提问于:2013-07-25 19:18
< >
分享
最佳答案
0

http://msdn.microsoft.com/zh-cn/library/system.xml.linq.xstreamingelement(v=vs.100).aspx

收获园豆:30
Yu | 专家六级 |园豆:12944 | 2013-07-25 20:02
其他回答(3)
0

直接用File.AppendText的方式写入就可以了~~~

收获园豆:5
路过秋天 | 园豆:4746 (老鸟四级) | 2013-07-26 00:40
0

SAX方法操作文件

http://stackoverflow.com/questions/3337953/working-with-very-huge-xml-file-in-c-sharp

http://www.codeproject.com/Articles/156982/How-to-Open-Large-XML-files-without-Loading-the-XM

搜索 c# work with big xml 

收获园豆:5
2012 | 园豆:18894 (专家六级) | 2013-07-26 08:34
0
XStreamingElement这个不大靠谱。
个人觉得好还是用从最后一个节点来循环找到对应的节点 找到了就插入子节点,没找到插入根节点,直接作为文本插入比较好。3楼的那几个代码大体上也都类似与这种想法,楼主可以看看。
收获园豆:10
````` | 园豆:14268 (专家六级) | 2013-07-26 09:35

是吗?我咋觉得第一种会好一些呢?文档中也说是可以处理大文件的。起码是结构化的,不用分析xml数据结构啊,处理文本有点太复杂了吧。

支持(0) 反对(0) 沧海一杰 | 园豆:28 (初学一级) | 2013-07-26 12:00

@沧海一杰: 那种是流的处理,如果真的xml大的话加载进去的消耗的内存绝对大的不行了。而操作节点 也就只读取一部分或者一个节点,找到了就添加节点,速度上以及资源上两者肯定相差很远很远。

支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-07-26 12:35

@imfunny: 

private void Sleep(int milliseconds)
        {
            var startTime = DateTime.Now;
            while (startTime.AddMilliseconds(milliseconds) <= DateTime.Now)
            {
                Application.DoEvents();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var filepath = @"d:\test\test.xml";
            Sub2(filepath);
        }


        static IEnumerable<XElement> StreamCustomerItem(string uri)
        {
            using (XmlReader reader = XmlReader.Create(uri))
            {
                reader.MoveToContent();

                // loop through Customer elements
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element
                        && reader.Name == "block")
                    {
                        var block = XElement.ReadFrom(reader) as XElement;
                        yield return block;
                    }
                }
            }
        }

        private void Sub2(string filepath)
        {
            for (var i = 0; i < 300; i++)
            {
                Debug.Print(i.ToString());

                var items = StreamCustomerItem(filepath);
                var xml = new XStreamingElement
                ("Root",
                    from item in items
                    select item,
                    new XElement
                    ("block",
                        new XAttribute("url", "http://www.baidu.com"),
                        new XElement("主图", new XCData("nodata"))
                    )
                );

                var newFile = filepath + "new";
                xml.Save(newFile);
                System.IO.File.Delete(filepath);
                System.IO.File.Move(newFile, filepath);

                GC.Collect();

                Sleep(100);
            }
        }

运行这段代码处理一个40M的文件几乎没有内存升高的现象存在。而用xmlDocument内存直接升高100多M,但这个里面有一个问题,难道就不能在原来的文件上直接写吗?就算用你的方法可以这样做吗?用这种做法比较耗时。
支持(0) 反对(0) 沧海一杰 | 园豆:28 (初学一级) | 2013-07-26 13:37

@沧海一杰: 

有点误会上面人家发的那个意思了。

XmlTextReader myTextReader = new XmlTextReader(filename);
myTextReader.WhitespaceHandling = WhitespaceHandling.None;
while (myTextReader.Read())
{
    if (myTextReader.NodeType == XmlNodeType.Element &&
        myTextReader.LocalName == "Reward" &&
        myTextReader.IsStartElement() == true)
        {
           
                myTextReader.Skip();
    }
}

看这个是如何读取节点进行比对的。

读取单一节点匹配,不是把整个文件给装载到xmlDocument中去。

    
支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-07-26 13:43

@imfunny: 其实我需要的功能很简单,就是如何给一个形如下的xml中append一个block结点,现在就是读的时候不能写,那我要怎么写回原来的文件呢,如果创建一个临时文件,写完后删除原文件,用临时文件替换原文件,这个流程有点不爽,有好一点的吗?

<Root>

<block></block> 

<block></block>

<block></block>

</Root>

支持(0) 反对(0) 沧海一杰 | 园豆:28 (初学一级) | 2013-07-26 14:12

@沧海一杰:  稍微写了几行代码 ,里面在写入文件的偏移量上有bug  写入位置为index 稍微调下应该就O了。文件读取以及写入肯定很快。楼主测试下。

        static void Main(string[] args)
        {
            int index = 0;

            var path = @"F:\c.xml";
            var regex = new Regex("<block[^>]*>(.*?)</block>", RegexOptions.Multiline);
            var tmp = string.Empty;

            using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\c.xml"))
            {

                do
                {
                    tmp += file.ReadLine();
                    if (regex.IsMatch(tmp))
                    {
                        index = tmp.Length - regex.Match(tmp).Length;
                        Console.WriteLine(tmp);
                        Console.WriteLine("退出");
                        break;
                    }
                }
                while (true);

            }

            var str = "<block></block>";

            var b = System.Text.ASCIIEncoding.ASCII.GetBytes(str);

            using (var f = File.OpenWrite(path))
            {

                f.Write(b, 0, b.Length);
            }
            Console.ReadLine();

        }
支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-07-26 15:03

@imfunny: 感谢你的热心,这个代码写我觉得肯定行得通,我没试,但代码里有正则会不会很慢呀,很大的XML文件呀。只是我写的代码是C#,不能像C语言那样都定义到文件的某个位置和字节,这样就失去C#的优势了,而且分析困难,不好维护。面向对象还是好一些,最终我还是选定了1楼的用法,就如我上面用到的方法,已经集成到项目里,内存一下就下去了4/5,但存取的速度上可能慢了点,但对整个流程几乎无影响。

支持(0) 反对(0) 沧海一杰 | 园豆:28 (初学一级) | 2013-07-26 15:09

@沧海一杰: 嗯。正则的速度是很快的。这样做其实就是一个查询节点,查询第一个匹配的节点,顺带得到了节点的起始位置,然后直接写入一个节点。理论上的速度会更快对性能的消耗也更低点就是了,没事,那种简单快捷用那个。

支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-07-26 15:13
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册