在内存中合并大量(2GB)XML(没有任何内存异常)

时间:2014-09-11 15:02:14

标签: c# .net xml merge out-of-memory

我想要一个最佳附加2个XML字符串的C#代码。它们都是相同的架构。我试过StreamReader / StreamWriter; File.WriteAllText; FileStream 我看到的问题是,它使用超过98%的物理内存,从而导致内存不足异常。

有没有一种方法可以在没有任何内存异常的情况下进行最佳合并?时间不是我关心的问题。

如果在内存中使用它将成为一个问题,那么还有什么可能更好?将其保存在文件系统上?

更多详情: 这是我的简单程序:提供更好的细节

static void Main(string[] args)
        {
            Program p = new Program();
            XmlDocument x1 = new XmlDocument();
            XmlDocument x2 = new XmlDocument();
            x1.Load("C:\\XMLFiles\\1.xml");
            x2.Load("C:\\XMLFiles\\2.xml");
            List<string> files = new List<string>();
            files.Add("C:\\XMLFiles\\1.xml");
            files.Add("C:\\XMLFiles\\2.xml");
            p.ConsolidateFiles(files, "C:\\XMLFiles\\Result.xml");
            p.MergeFiles("C:\\XMLFiles\\Result.xml", x1.OuterXml, x2.OuterXml, "<Data>", "</Data>");
            Console.ReadLine();

        }

        public void ConsolidateFiles(List<String> files, string outputFile)
        {
            var output = new StreamWriter(File.Open(outputFile, FileMode.Create));
            output.WriteLine("<Data>");
            foreach (var file in files)
            {
                var input = new StreamReader(File.Open(file, FileMode.Open));
                string line;
                while (!input.EndOfStream)
                {
                    line = input.ReadLine();
                    if (!line.Contains("<Data>") &&
                        !line.Contains("</Data>"))
                    {
                        output.Write(line);
                    }
                }
            }
            output.WriteLine("</Data>");
        }
        public void MergeFiles(string outputPath, string xmlState, string xmlFederal, string prefix, string suffix)
        {
            File.WriteAllText(outputPath, prefix);
            File.AppendAllText(outputPath, xmlState);
            File.AppendAllText(outputPath, xmlFederal);
            File.AppendAllText(outputPath, suffix);
        }

XML示例: <Data> </Data>附加在开头&amp;端

XML 1:<Sections> <Section></Section> </Sections>

XML 2:<Sections> <Section></Section> </Sections>

合并:<Data> <Sections> <Section></Section> </Sections> <Sections> <Section></Section> </Sections> </Data>

4 个答案:

答案 0 :(得分:0)

试试这个,基于流的方法,避免一次将所有xml加载到内存中。

    static void Main(string[] args)
    {
        List<string> files = new List<string>();
        files.Add("C:\\XMLFiles\\1.xml");
        files.Add("C:\\XMLFiles\\2.xml");
        ConsolidateFiles(files, "C:\\XMLFiles\\Result.xml");
        Console.ReadLine();
    }

    private static void ConsolidateFiles(List<String> files, string outputFile)
    {
        using (var output = new StreamWriter(outputFile))
        {
            output.WriteLine("<Data>");
            foreach (var file in files)
            {
                using (var input = new StreamReader(file, FileMode.Open))
                {
                    while (!input.EndOfStream)
                    {
                        string line = input.ReadLine();
                        if (!line.Contains("<Data>") &&
                            !line.Contains("</Data>"))
                        {
                            output.Write(line);
                        }
                    }
                }
            }
            output.WriteLine("</Data>");
        }
    }

更好的方法是使用XmlReader(http://msdn.microsoft.com/en-us/library/system.xml.xmlreader(v=vs.90).aspx)。这将为您提供专门为xml设计的流阅读器,而不是用于阅读常规文本的StreamReader。

答案 1 :(得分:0)

看看here Teoman Soygul给出的答案似乎正是您所寻找的。

答案 2 :(得分:0)

这是未经测试的,但我会使用TextReader和TextWriter在这些行上做一些事情。您不希望将所有XML文本读入内存或将其存储在字符串中,并且您不希望使用XElement / XDocument / etc.在中间的任何地方。

using (var writer = new XmlTextWriter("ResultFile.xml")
{
    writer.WriteStartDocument();
    writer.WriteStartElement("Data");
    using (var reader = new XmlTextReader("XmlFile1.xml")
    {
        reader.Read();
        while (reader.Read())
        {
            writer.WriteNode(reader, true);
        }
    }
    using (var reader = new XmlTextReader("XmlFile2.xml")
    {
        reader.Read();
        while (reader.Read())
        {
            writer.WriteNode(reader, true);
        }
    }
    writer.WriteEndElement("Data");
}

再一次不能保证这个确切的代码可以按原样运行(或者它甚至可以编译),但我认为这是你正在寻找的想法。首先从File1流式传输数据并将其直接写入结果文件。然后,从File2流式传输数据并将其写出。在任何时候都不应该在内存中存储完整的XML文件。

答案 3 :(得分:-1)

你必须去文件系统,除非你有很多RAM 一个简单的方法:

File.WriteAllText("output.xml", "<Data>");
File.AppendAllText("output.xml", File.ReadAllText("xml1.xml"));
File.AppendAllText("output.xml", File.ReadAllText("xml2.xml"));
File.AppendAllText("output.xml", "</Data>");

另一:

var fNames = new[] { "xml1.xml", "xml2.xml" };
string line;
using (var writer = new StreamWriter("output.xml"))
{
    writer.WriteLine("<Data>");
    foreach (var fName in fNames)
    {
        using (var file = new System.IO.StreamReader(fName))
        {
            while ((line = file.ReadLine()) != null)
            {
                writer.WriteLine(line);
            }
        }
    }
    writer.WriteLine("</Data>");
}

所有这一切的前提是xml1.xml和xml2.xml中没有架构或标签 如果是这种情况,只需要省略它们的代码。