【问题标题】:PowerShell throws a System.OutOfMemoryException on reading a large (50 MB) XML documentPowerShell 在读取大型 (50 MB) XML 文档时引发 System.OutOfMemoryException
【发布时间】:2014-02-11 10:01:44
【问题描述】:

我们正在运行以下脚本:

[xml]$products = Get-Content C:\fso\products.xml

并收到以下错误:

System.OutOfMemoryException

我们假设这是因为 XML 文件很大。该解决方案可能涉及一次读取一行 XML。 我们如何处理这个文件?例如,我们如何计算元素的数量?或者,我们如何将元素名称打印到控制台窗口?

我们目前正在查看此链接:

http://blogs.technet.com/b/stephap/archive/2009/05/27/choking-on-very-large-xml-files.aspx

XML结构如下:

<?xml version="1.0" encoding="UTF-8"?>
    <dataroot xmlns:od="urn:schemas-microsoft-com:officedata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="Products.xsd" generated="2014-01-21T08:21:41">
        <Products>
            <upc>0000000000001</upc>
            <description>BASICS $1.00</description>
            <cost>0.6</cost>
            <normal_price>1</normal_price>
            <pricemethod>0</pricemethod>
            <target_margin>0</target_margin>
            <department>34</department>
            <pack>1</pack>
            <tax>3</tax>
            <foodstamp>0</foodstamp>
            <scale>0</scale>
            <dsd>0</dsd>
            <modified>2014-01-04T10:23:55</modified>
            <cost_modified>2012-11-11T11:20:58</cost_modified>
            <active>1</active>
            <advertised>0</advertised>
            <whomodified>170</whomodified>
            <longdescription>TEAR ISSUE</longdescription>
            <seconddescription>ROLL START</seconddescription>
            <discount>1</discount>
            <wicable>0</wicable>
            <validage>0</validage>
            <deleted>0</deleted>
            <attributes>2056</attributes>
            <Created>2005-02-16T09:53:00</Created>
            <CreatedBy>1</CreatedBy>
            <Points>0</Points>
        </Products>
        <Products>
            <upc>0000000000357</upc>
            <description>CHARMIN BATHROOM TISSUE</description>
            <cost>5.81</cost>
            <normal_price>7.99</normal_price>
            <pricemethod>0</pricemethod>
            <target_margin>0</target_margin>
            <department>4</department>
            <pack>1</pack>
            <size>OVERLIMIT</size>
            <tax>2</tax>
            <foodstamp>0</foodstamp>
            <scale>0</scale>
            <dsd>0</dsd>
            <modified>2010-06-30T23:55:00</modified>
            <active>0</active>
            <advertised>0</advertised>
            <whomodified>30</whomodified>
            <longdescription>CHARMIN BATHROOM TISSUE</longdescription>
            <discount>1</discount>
            <wicable>0</wicable>
            <validage>0</validage>
            <deleted>0</deleted>
            <attributes>2048</attributes>
            <Created>2005-02-16T09:53:00</Created>
            <CreatedBy>1</CreatedBy>
            <Points>0</Points>
        </Products>

【问题讨论】:

  • 我刚刚在一个 1.5GB(是,GB)的 XML 文件上尝试了 Get-Content 方法。它最终填充了服务器 70GB 的内存,并继续处理页面文件。转换为 [xml] 是不可能的内存占用...

标签: xml powershell memory-management large-files


【解决方案1】:

使用 XPath 查询此类文档可能会更好。 XPath 通常可以在不需要将整个文档加载到 DOM 树中的流模式下工作。

Select-Xml:

以下将计算 XML 文件中的所有元素:

Select-Xml -Path C:\fso\products.xml -Xpath "count(//*)"

通过这种方式,您可以获取您所关注的 XML 的小 sn-ps 或对它们进行计算。

见:http://technet.microsoft.com/en-us/library/hh849968.aspx

【讨论】:

  • 这更容易使用,因此我们将其标记为答案。
  • @jessehouwing:我想了解有关在使用 Xpath/Select-Xml 时使用流式传输的更多信息。你碰巧有什么好的资源?
  • 我已经尝试过这种方法,在我的 1.5GB XML 文件上它仍然使用 8GB 内存,但大约 15 分钟后完成。很棒的演出!有一种使用流的方法可以降低内存使用量......
  • 这完全取决于操作的类型,我还怀疑您如何处理提取的数据。仅在具有足够可用内存的快速循环中创建大量字符串可能会导致车库收集有点滞后,从而导致比严格需要的消耗更高。
  • 对于真正的流媒体,请查看:msdn.microsoft.com/en-us/library/…。更多关于 XPath 文档和 Xml 文档之间的区别可以在这里找到:hashname.wordpress.com/tag/…blogs.msdn.com/b/xmlteam/archive/2011/09/14/…
【解决方案2】:

对于这么大的文件,一次一行会非常慢。

您可以使用 Get-Content -Readcount 一次处理大块行(-ReadCount 1000 将为您提供每个 1000 行的数组)。

【讨论】:

  • 运行时 [xml]$products = get-content -ReadCount 1 $xmlPath;我们仍然收到 System.OutOfMemoryException。什么给了?
  • 您不能将结果转换为 [XML]。仅当您可以读取整个文件时,这才有效。您需要将其作为字符串数据读入,并使用 -match 和 -replace 等数组运算符对其进行处理。
  • 如果您的 XML 是由多个相同类型的节点(如书籍)构建的,并且您从缓冲的阅读器中解析它们,并将它们一一转换为 XML,则此建议可能很有用。 .
  • 对于这种情况,使用 get-content 和 -delimiter 可能会更好。将结束节点标记作为分隔符,然后将每个段通过 foreach-object 进行处理。这样您就不必担心一个节点可能跨越两个 readcount 段。
猜你喜欢
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 2011-12-02
  • 1970-01-01
  • 2018-08-08
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
相关资源
最近更新 更多