Пакетная обработка php fgetcsv

У меня есть довольно большой CSV-файл (по крайней мере, для Интернета), который я не контролирую. В нем около 100 тысяч строк, и он будет только увеличиваться.

Я использую Drupal Module Feeds для создания узлов на основе этих данных, и их синтаксический анализатор группирует синтаксический анализ в группы по 50 строк. Однако их синтаксический анализатор неправильно обрабатывает кавычки и не может проанализировать около 60% CSV-файла. fgetcsv работает, но, насколько я могу судить, не объединяет вещи.

При попытке прочитать весь файл с помощью fgetcsv PHP в конечном итоге заканчивается память. Поэтому я хотел бы иметь возможность разбивать вещи на более мелкие куски. Это возможно?


person Malfist    schedule 03.01.2011    source источник


Ответы (3)


fgetcsv() работает, читая по одной строке из заданного указателя файла. Если PHP не хватает памяти, возможно, вы пытаетесь разобрать весь файл сразу, поместив его все в гигантский массив. Решением было бы обрабатывать его построчно, не сохраняя в большом массиве.

Чтобы более точно ответить на вопрос о пакетной обработке, прочитайте n строк из файла, а затем используйте ftell(), чтобы найти место в файле, на котором вы закончили. Запишите этот момент, и затем вы сможете вернуться к нему в какой-то момент в будущем, вызвав fseek() перед fgetcsv().

person mfonda    schedule 03.01.2011

Что ж, создадим функцию для разбора кучи строк:

function parseLines(array $lines) {
    foreach ($lines as $line) {
        //insert line into new node
    }
}

Затем просто объедините его:

$numberOfLinesToBatch = 50;
$f = fopen($file, 'r');
if (!$f) die('implement better error checking');

$buffer = array();
while ($row = fgetcsv($f)) {
    $buffer[] = $row;
    if (count($buffer) >= $numberOfLinesToBatch) {
        parseLines($buffer);
        $buffer = array();
    }
}
if (!empty($buffer)) {
    parseLines(buffer);
}

fclose($f);

Он передает данные, и вы можете настроить, сколько строк он буферизует, изменив переменную...

person ircmaxell    schedule 03.01.2011

Я подозреваю, что проблема заключается в том, что вы храните слишком много информации в памяти, а не в том, как вы читаете файл CSV с диска. (т. е.: fgetcsv будет считывать только строку за раз, поэтому, если данные в одной строке приводят к нехватке памяти, у вас проблемы.)

Таким образом, вам просто нужно использовать подход, при котором вы:

  1. Прочитать 'x' строк в массив.
  2. Обработать эту информацию
  3. Очистите все временные переменные/массивы.
  4. Повторяйте до FEOF.

В качестве альтернативы вы можете выполнить обработку CSV через версию PHP для командной строки и использовать собственный php.ini, который имеет гораздо больший лимит памяти.

person John Parker    schedule 03.01.2011