Использование fseek для начала чтения CSV после определенного количества строк - PullRequest
0 голосов
/ 02 марта 2012

Я использую текущий код для чтения файла 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 Ответ

3 голосов
/ 02 марта 2012

Время ожидания можно обойти, используя

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>";
...