将非常大的文件从xml转换为csv

目前我正在使用以下代码片段将带有XML数据的.txt文件转换为.CSV格式。 我的问题是,目前这适用于大约100-200 mbs的文件,并且转换时间非常短(最多1-2分钟),但是我现在需要它来处理更大的文件(每个1-2 GB)文件)。 目前该程序冻结了计算机,使用此function转换大约需要30-40分钟。 不知道我将如何继续更改此function。 任何帮助将不胜感激!

  string all_lines = File.ReadAllText(p); all_lines = "" + all_lines + ""; XmlDocument doc_all = new XmlDocument(); doc_all.LoadXml(all_lines); StreamWriter write_all = new StreamWriter(FILENAME1); XmlNodeList rows_all = doc_all.GetElementsByTagName("XML"); foreach (XmlNode rowtemp in rows_all) { List children_all = new List(); foreach (XmlNode childtemp in rowtemp.ChildNodes) { children_all.Add(Regex.Replace(childtemp.InnerText, "\\s+", " ")); } write_all.WriteLine(string.Join(",", children_all.ToArray())); } write_all.Flush(); write_all.Close(); 

样本输入::

  1,4,7,,5 hello,there,my,name,is,jack, last,name,missing,above 3,6,7,,8,4  1,5,7,,3hello,there,my,name,is,mary,jane last,name,not,missing,above3,6,7,,8,4 

样本输出::

 1,4,7,,5,hello,there,my,name,is,jack,,last,name,missing,above,3,6,7,,8,4 1,5,7,,3,hello,there,my,name,is,mary,jane,last,name,not,missing,above,3,6,7,,8,4 

您需要采用流式处理方法,因为您当前正在将整个2Gb文件读入内存然后进行处理。 您应该阅读一些XML,写一些CSV并继续这样做,直到您处理完所有。

可能的解决方案如下:

 using (var writer = new StreamWriter(FILENAME1)) { foreach (var element in StreamElements(r, "XML")) { var values = element.DescendantNodes() .OfType() .Select(e => Regex.Replace(e.Value, "\\s+", " ")); var line = string.Join(",", values); writer.WriteLine(line); } } 

其中StreamElements的灵感来自于Jon Skeet在XmlReader中对XElement的流式传输,以回答这个问题 。 我做了一些更改来支持你的’无效’XML(因为你没有root元素):

 private static IEnumerable StreamElements(string fileName, string elementName) { var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }; using (XmlReader reader = XmlReader.Create(fileName, settings)) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (reader.Name == elementName) { var el = XNode.ReadFrom(reader) as XElement; if (el != null) { yield return el; } } } } } } 

如果您准备考虑采用完全不同的方式,请下载Saxon-EE 9.6,获取评估许可证,然后运行以下流式XSLT 3.0代码:

      
     

它因File.ReadAllText(p);冻结File.ReadAllText(p);

不要将完整的文件读入内存。 (这将首先开始交换,然后暂停你的CPU,因为没有更多的内存可用)

使用分块方法:逐行读取,逐行转换,逐行写入。

使用一些较低级别的XML Reader类,而不是XmlDocument

有两种变体。 首先是隐藏程序冻结,使用BackgroundWorker。 第二:逐字符串地读取文本文件,使用任何Reader(Xml或任何文本\文件)。 您可以组合这些变体。