使用fseek在一定数量的行之后开始读取CSV

时间:2012-03-02 12:19:08

标签: php csv fgetcsv

我正在使用当前代码读取csv文件并将其添加到数组中:

    echo "starting CSV import<br>";
    $current_row = 1; 
    $handle = fopen($csv, "r"); 
    while ( ($data = fgetcsv($handle, 10000, ",") ) !== FALSE ) 
    { 
        $number_of_fields = count($data); 
        if ($current_row == 1) { 
        //Header line 
            for ($c=0; $c < $number_of_fields; $c++) 
            { 
                $header_array[$c] = $data[$c]; 
            } 
        } else { 
        //Data line 
            for ($c=0; $c < $number_of_fields; $c++) 
            { 
                $data_array[$header_array[$c]] = $data[$c]; 
            } 

            array_push($products, $data_array);

        } 
        $current_row++; 
    } 
    fclose($handle); 
    echo "finished CSV import <br>";

但是,当使用非常大的CSV时,服务器上会超时,或者内存限制错误。

我想要一个分阶段的方法,所以在第一个说出100行后,它将刷新页面,从第101行开始。

我可能会使用元刷新和URL参数来执行此操作。

我只需要知道如何调整上面的代码,从我告诉它的那一行开始。

我已经研究过fseek(),但我不知道如何在这里实现它。

你能帮忙吗?

1 个答案:

答案 0 :(得分:3)

可以使用

规避时间
ignore_user_abort(true);
set_time_limit(0);

当遇到内存限制问题时,退一步看看你正在对你正在处理的数据做些什么可能是明智之举。您是否将数据推送到数据库中?从数据中计算出某些东西,但不需要存储实际数据......

你真的需要将行(array_push($products, $data_array);)推入数组(以便以后处理)吗?你可以直接写入数据库吗?或直接计算?或者直接构建一个html <table>?或者你正在做什么,然后在while()循环内,而不是先将所有内容都推入数组中?

如果你能够对处理进行分块,我猜你根本不需要那个数组。否则你必须为每个块恢复数组 - 不能解决内存问题。

如果您可以设法更改处理算法以减少内存/时间浪费,那么您应该认真考虑任何需要往返浏览器的分块处理(由于许多性能和安全原因......)。

无论如何,您可以随时使用ftell()识别当前流偏移,并使用fseek()重新设置到该位置。您只需要将该整数传递给下一次迭代。


此外,您不需要内部for()循环。这应该产生相同的结果:

<?php

$products = array();
$cols = null;
$first = true; 

$handle = fopen($csv, "r"); 
while (($data = fgetcsv($handle, 10000, ",")) !== false)  { 
    if ($first) { 
        $cols = $data;
        $first = false;
    } else { 
        $products[] = array_combine($cols, $data);
    }
}

fclose($handle); 
echo "finished CSV import <br>";