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

本文关键字:xml 转换 csv 文件 非常 | 更新日期: 2023-09-27 17:57:07

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

    string all_lines = File.ReadAllText(p);
    all_lines = "<Root>" + all_lines + "</Root>";
    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<string> children_all = new List<string>();
        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();

示例输入::

 <XML><DSTATUS>1,4,7,,5</DSTATUS><EVENT> hello,there,my,name,is,jack,</EVENT>
     last,name,missing,above <ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG> </XML>
 <XML><DSTATUS>1,5,7,,3</DSTATUS><EVENT>hello,there,my,name,is,mary,jane</EVENT>
     last,name,not,missing,above<ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG></XML>

示例输出::

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

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

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

可能的解决方案如下:

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

StreamElements的灵感来自乔恩·斯基特(Jon Skeet)在回答这个问题时从XmlReader中流出的XElement。 我做了一些更改来支持您的"无效"XML(因为您没有根元素):

private static IEnumerable<XElement> 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 代码:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="main">
  <xsl:stream href="input.xml">
    <xsl:for-each select="*/*">
       <xsl:value-of select="*!normalize-space()" separator=","/>
       <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
  </xsl:stream>
</xsl:template>
</xsl:stylesheet>

>由于File.ReadAllText(p);而冻结

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

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

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

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