2015-09-17 6 views
1

Доброе утро, Я действительно переживаю тяжелые уроки, пытаясь обрабатывать огромные файлы csv до 4 ГБ.Проблема с огромным CSV-файлом с php fgetcsv - понимание потребления памяти

Цель состоит в том, чтобы искать некоторые элементы в файле csv (данные данных Amazon) с помощью данного режима браузера, а также с помощью определенного элемента id (ASIN). Чтобы получить сочетание существующих элементов (в моей базе данных) плюс некоторые дополнительные новые темы, так как время от времени элементы исчезают на рынке. Я также фильтрую название элементов, потому что есть много элементов, использующих то же самое.

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

Я установил ограничение на память до 4096 МБ, ограничение времени равно 0. Сервер имеет 64 ГБ RAM и два жестких диска SSD.

Может кто-нибудь, пожалуйста, загляните в мой кусок кода и объясните, как возможно, что у них не хватает памяти и что важнее, как используется память?

private function performSearchByASINs() 
{ 
    $found = 0; 
    $needed = 0; 
    $minimum = 84; 
    if(is_array($this->searchASINs) && !empty($this->searchASINs)) 
    { 
     $needed = count($this->searchASINs); 
    } 
    if($this->searchFeed == NULL || $this->searchFeed == '') 
    { 
     return false; 
    } 
    $csv = fopen($this->searchFeed, 'r'); 
    if($csv) 
    { 
     $l = 0; 
     $title_array = array(); 
     while(($line = fgetcsv($csv, 0, ',', '"')) !== false) 
     { 
      $header = array(); 
      if(trim($line[6]) != '') 
      { 
       if($l == 0) 
       { 
        $header = $line; 
       } 
       else 
       { 
        $asin = $line[0]; 
        $title = $this->prepTitleDesc($line[6]); 
        if(is_array($this->searchASINs) 
        && !empty($this->searchASINs) 
        && in_array($asin, $this->searchASINs)) //search for existing items to get them updated 
        { 
         $add = true; 
         if(in_array($title, $title_array)) 
         { 
          $add = false; 
         } 
         if($add === true) 
         { 
          $this->itemsByASIN[$asin] = new stdClass(); 
          foreach($header as $k => $key) 
          { 
           if(isset($line[$k])) 
           { 
            $this->itemsByASIN[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>')); 
           } 
          } 
          $title_array[] = $title; 
          $found++; 
         } 
        } 
        if(($line[20] == $this->bnid || $line[21] == $this->bnid) 
        && count($this->itemsByKey) < $minimum 
        && !isset($this->itemsByASIN[$asin])) // searching for new items 
        { 
         $add = true; 
         if(in_array($title, $title_array)) 
         { 
          $add = false; 
         } 
         if($add === true) 
         { 
          $this->itemsByKey[$asin] = new stdClass(); 
          foreach($header as $k => $key) 
          { 
           if(isset($line[$k])) 
           { 
            $this->itemsByKey[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>'));         
           } 
          } 
          $title_array[] = $title; 
          $found++; 
         } 
        } 
       } 
       $l++; 
       if($l > 200000 || $found == $minimum) 
       { 
        break; 
       } 
      } 
     } 
     fclose($csv); 
    } 
} 

ответ

0

Очень сложно управлять большими данными с использованием массива без возникновения проблемы с таймаутом. Вместо этого, почему бы не разобрать этот файл данных в таблице базы данных и сделать тяжелый подъем оттуда.

+0

Ну. Я просто подумал, что производительность над всеми будет лучше не использовать базу данных, а вместо этого использовать простые файлы csv, так как Amazon требует регулярно обновлять данные (по крайней мере каждые 24 часа), что означает сравнение базы данных с updatefeeds который может появляться каждые 30 минут. –

+0

Если возможно, попробуйте разбить большой файл на несколько файлов. Найдите инструменты, которые могут это сделать – MACMAN

+0

Хмм, я все еще надеюсь, что если кто-нибудь сможет объяснить, как используется подробная память, ее можно обрабатывать в пределах одного файла. У меня уже 82 файла для обработки. –

0

Вы пробовали это? SplFileObject::fgetcsv

<?php 
$file = new SplFileObject("data.csv"); 
while (!$file->eof()) { 
    //your code here 
} 
?> 

Вы работаете из памяти, потому что вы используете переменные, и вы никогда не делаете в unset(); и использовать слишком много вложенных foreach. Вы можете уменьшить этот код в большем количестве функций. Решение должно быть, вместо этого используйте реальную базу данных.

+0

Я не хочу использовать базу данных, так как я должен обновлять эти каналы на регулярной основе. Я использую три массива, которые собирают данные и могут содержать максимум 200 значений (каждый). Четвертый массив - это заголовок $, который сбрасывается для каждой строки, и я не перезаписываю переменные, так как они сбрасываются после каждой строки, прочитанной в цикле while. Но спасибо за публикацию SplFileObject - я буду читать руководство –

+0

Я пробовал это, но не помог - но спасибо в любом случае! –

1

Я знаю, что мой ответ немного запоздалый, но у меня была аналогичная проблема с fgets() и вещи, основанные на fgets(), как функция SplFileObject->current(). В моем случае это было в системе Windows при попытке прочитать файл + 800MB. Я думаю, что fgets() не освобождает память предыдущей строки в цикле. Таким образом, каждая прочитанная строка оставалась в памяти и позволяла ошибкам со смертельным исходом. Я исправил его, используя fread($lineLength), но это немного сложнее, так как вы должны указать длину.

 Смежные вопросы

  • Нет связанных вопросов^_^