在内存中合并巨大的(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>
试试这个方法,它是一种基于流的方法,可以避免一次将所有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内部没有模式或标记为前提如果是这种情况,只需编写代码来省略它们。