【问题标题】:PHP script to convert csv to XML not working for large file (around 1GB)将 csv 转换为 XML 的 PHP 脚本不适用于大文件(大约 1GB)
【发布时间】:2016-02-18 14:10:57
【问题描述】:

我们编写了以下 PHP 脚本来将 CSV 文件转换为 XML 文件。但是它卡住了,没有从 while 循环中出来 saveXML。

CSV 文件大小约为 1GB,CSV 文件中的行数约为 1,00,000。

由于行数过多,无法正常工作。

我的问题是:我们如何修改以下代码,使其适用于大文件?

<?php
    $delimit = "," ;        
    $row_count = 0 ;

    $inputFilename = "feed.csv" ;

    $outputFilename   = 'output.xml';
    $inputFile  = fopen($inputFilename, 'rt');

    $headers = fgetcsv($inputFile);
    $doc  = new DomDocument();
    $doc->formatOutput   = true;

    $root = $doc->createElement('rows');  
    $root = $doc->appendChild($root);     

    while (($row = fgetcsv($inputFile)) !== FALSE)
    {
        $container = $doc->createElement('row'); 
        foreach ($headers as $i => $header)
        {
            $arr = explode($delimit, $header);
            foreach ($arr as $j => $ar)
            {           
                $child = $doc->createElement(preg_replace("/[^A-Za-z0-9]/","",$ar));
                $child = $container->appendChild($child); 

                $whole = explode($delimit, $row[$i]);
                $value = $doc->createTextNode(ltrim( rtrim($whole[$j], '"') ,'"')); 
                $value = $child->appendChild($value); 
            }
        }
        $root->appendChild($container);
        echo "." ;
    }

    echo "Saving the XML now" ;
    $result = $doc->saveXML();

    echo "Writing to XML file now" ;
    $handle = fopen($outputFilename, "w");
    fwrite($handle, $result);
    fclose($handle);

    return $outputFilename;

?>

已编辑:

在 php.ini 中,memory_limit 和执行时间设置为无限制和最大。我正在使用命令行执行。

【问题讨论】:

  • 你有 PHP 显示错误吗?总是在开发代码时,error_reporting(E_ALL); ini_set('display_errors', 1); 在脚本的顶部。很可能您正在耗尽您的内存限制。如果这是一次性的,您可以暂时增加它。
  • 将内存限制增加到 3GB 确实不是一种选择。请改用php.net/manual/en/book.xmlwriter.php。我相信如果您遵循本教程codeinthehole.com/writing/creating-large-xml-files-with-php,您可以自己回答问题。
  • @Alex Blex,我认为,您的第二个链接可能会解决问题。让我现在检查一下。
  • XMLWriter 可能是 DOM 上的解决方案
  • 这里发生了几件事。在while 循环中使用两个嵌套的for 循环将一个非常大的csv 迭代地读取到一个不断增长的xml 树中。考虑在循环外定义标头(xml 节点)并在一个循环中附加 csv 值。请发布示例 csv/desired xml 以进行演示。我什至看到了一个 XSLT 解决方案,它可以绑定几个较小的临时文档。这是一个很好的问题。伙计们,OP 获得了所有乐趣!

标签: php xml csv


【解决方案1】:

正如您所注意到的,您遇到了如此大的输入/输出的资源问题。

您使用的输入处理,fgetcsv() 已经非常有效,因为它一次读取一行。 在这种情况下,输出是问题所在。您将整个 1GB 原始文本存储到一个 DOMDocument 对象中,这会增加所需内存的大量开销。

但是根据您的代码,您只需将 xml 写回文件,因此在运行时您并不需要它作为 DOMDocument。

最简单的解决方案是将xml字符串构建为字符串并将其写入csv每一行的输出文件:使用'a'(fopen($outputfilename, "a");打开输出文件的句柄,在循环,每次循环运行时写入每个 csv-to-xml-ified elment,在循环后写入 xml 页脚

【讨论】:

    【解决方案2】:

    很可能是 DomDocument 的(错误)使用导致了您的内存问题(@cypherabe 已回答)。

    但我建议您查看 XmlWriter http://php.net/manual/en/book.xmlwriter.php

    ,而不是建议的字符串连接解决方​​案

    XmlWriter 扩展表示一个编写器,它提供了一种非缓存、只进的方式来生成包含 XML 数据的流或文件。 此扩展可用于面向对象的样式或程序样式。

    它已经与 PHP 5.2.1 版本捆绑在一起

    【讨论】:

    • 查看我对 OP 的评论。
    【解决方案3】:

    http://www.prestatraining.com/12-tips-to-optimise-your-php-ini-file-for-prestashop/

    查看内存和大小限制部分(忽略它是关于 prestashop 的事实)

    听起来您在服务器上的 PHP 设置在执行时超时。如果您尝试处理 1GB 的文件,如果您有标准的 PHP.ini 设置,如果它失败了,我不会感到惊讶。

    【讨论】:

      猜你喜欢
      • 2011-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-06
      • 2015-09-04
      • 1970-01-01
      • 2012-12-31
      相关资源
      最近更新 更多