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

本文关键字:内存 XML 任何 异常 2GB 合并 巨大 | 更新日期: 2023-09-27 18:21:36

我想要一个最佳附加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示例:CCD_ 2被附加在开头&结束

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

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

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

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

试试这个方法,它是一种基于流的方法,可以避免一次将所有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。

看看这里Teoman Soygul给出的答案似乎就是你想要的。

这是未经测试的,但我会使用TextReader和TextWriter来做一些类似的事情。您不希望将所有XML文本读取到内存中或将其存储在字符串中,也不希望使用XElement/XDocument等。在中间的任何地方。

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文件。

如果您在64位上运行,请尝试以下操作:转到项目属性->构建选项卡->平台目标:将"Any CPU"更改为"x64"。

这解决了我在内存中加载巨大XML文件的问题。

除非有大量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内部没有模式或标记为前提如果是这种情况,只需编写代码来省略它们。