Плохая производительность в PHP.С большими файлами память взрывается!Как я могу рефакторинг? - PullRequest
1 голос
/ 21 декабря 2010

У меня есть функция, которая удаляет строки из файлов.Я работаю с большими файлами (более 100 Мб).У меня есть PHP-память с 256 МБ, но функция, которая обрабатывает полосу из строк, взрывается с помощью файла CSV размером 100 МБ.

Что должна сделать функция, это:

Первоначально у меня естьCSV, как:

Copyright (c) 2007 MaxMind LLC.Все права защищены.locId, страна, регион, город, postalCode, широта, долгота, metroCode, areaCode 1, "O1", "", "", "", 0.0000,0.0000 ,, 2, "AP", "", "", "", 35.0000,105.0000 ,, 3," EU "," "," "," ", 47.0000,8.0000 ,, 4," AD "," "," "," ", 42.5000,1.5000 ,, 5,"AE "," "," "," ", 24.0000,54.0000 ,, 6," AF "," "," "," ", 33.0000,65.0000 ,, 7," AG "," "," ","", 17.0500, -61.8000 ,, 8," AI "," "," "," ", 18.2500, -63.1667 ,, 9," AL "," ",", "", 41.0000,20.0000 ,,

Когда я передаю файл CSV этой функции, я получаю:

locId, страна, регион, город, postalCode, широта, долгота, metroCode, areaCode 1, "O1"," "," "," ", 0,0000,0.0000 ,, 2," AP "," "," "," ", 35.0000,105.0000 ,, 3," EU "," "," "," ", 47.0000,8.0000 ,, 4, "AD", "", "", "", 42.5000,1.5000 ,, 5, "AE", "", "", "", 24.0000,54.0000 ,, 6, "AF"," "," "," ", 33.0000,65.0000 ,, 7," AG "," "," "," ", 17.0500, -61.8000 ,, 8," AI "," "," ","", 18.2500, -63.1667 ,, 9," AL "," "," "," ", 41.0000,20.0000 ,,

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

Функция:

 public function deleteLine($line_no, $csvFileName) {

  // this function strips a specific line from a file
  // if a line is stripped, functions returns True else false
  //
  // e.g.
  // deleteLine(-1, xyz.csv); // strip last line
  // deleteLine(1, xyz.csv); // strip first line

  // Assigna o nome do ficheiro
  $filename = $csvFileName;

  $strip_return=FALSE;

  $data=file($filename);
  $pipe=fopen($filename,'w');
  $size=count($data);

  if($line_no==-1) $skip=$size-1;
  else $skip=$line_no-1;

  for($line=0;$line<$size;$line++)
   if($line!=$skip)
    fputs($pipe,$data[$line]);
   else
    $strip_return=TRUE;

  return $strip_return;
 }

Можно выполнить рефакторинг этой функции, чтобы она не была взорвана256 МБ PHP памяти?

Дайте мне несколько подсказок.

С наилучшими пожеланиями,

Ответы [ 3 ]

2 голосов
/ 21 декабря 2010

Проблема вашего выброса - функция file, которая переносит весь файл в память.Чтобы преодолеть это, вам нужно прочитать файл построчно, записать все, кроме удаляемой строки, во временный файл и, наконец, переименовать временный файл.

public function deleteLine($line_no, $csvFileName) {

        // get a temp file name in current working directory..you can use
        // any other directory say /tmp
        $tmpFileName = tempnam(".", "csv");

        $strip_return=FALSE;

        // open input file for reading.
        $readFD=fopen($csvFileName,'r');

        // temp file for writing.
        $writeFD=fopen($tmpFileName,'w');

        // check for fopen errors.

        if($line_no==-1) {
                $skip=$size-1;
        } else {
                $skip=$line_no-1;
        }

        $line = 0;

        // read lines from input file one by one.
        // write all lines except the line to be deleted.
        while (($buffer = fgets($readFD)) !== false) {
                if($line!=$skip)
                        fputs($writeFD,$buffer);
                else
                        $strip_return=TRUE;
                $line++;
        }

        // rename temp file to input file.    
        rename($tmpFileName,$csvFileName);

        return $strip_return;
}
1 голос
/ 21 декабря 2010

ну, самый простой ответ - не делай этого с PHP.Серьезно, sed будет работать намного лучше для этого, потому что весь файл никогда не будет в памяти.Проверьте эти oneliners , но по существу:

sed '1d' filename

Я знаю, что системные вызовы не одобряются, но я думаю, что это может быть случай, когда один гарантирован.

0 голосов
/ 21 декабря 2010

Метод file () считывает весь файл в массив одновременно.Я полагаю, что здесь все взрывается.Возможно, вы захотите иметь второй дескриптор fopen () для вашего входного файла, чтобы вы могли читать по одной строке за раз.

Если вы хотите обрабатывать эту задачу с помощью PHP, это нормально.Но этот тип вещей, вероятно, лучше оставить для чего-то вроде awk

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...