Funzionalità con performance inadeguate in PHP. Con la memory di grandi file esplode! Come posso refactoring?

Ho una function che rimuove le linee dai file. Sto gestendo con file di grandi size (più di 100 Mb). Ho la memory PHP con 256 MB, ma la function che gestisce con la striscia fuori dalle righe esplode con un file CSV da 100 MB.

Ciò che la function deve fare è questa:

Originariamente ho il CSV come:

Copyright (c) 2007 MaxMind LLC. Tutti i diritti riservati. luogo, paese, regione, città, codice postale, latitudine, longitudine, metroCode, areaCodice 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 ,,

Quando passo il file CSV a questa function ho ottenuto:

luogo, paese, regione, città, codice postale, latitudine, longitudine, metroCode, areaCodice 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 ,,

Rimuove solo la prima row, niente di più. Il problema è l'esecuzione di questa function con file di grandi size, fa esplodere la memory.

La function è:

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 // // eg // 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; } 

È ansible refactoring questa function per non saltare in aria con la memory di 256 MB di PHP?

Dammi qualche indizio

I migliori saluti,

Il problema del tuo blowout è la function file che port in memory l'integer file. Per ovviare a ciò è necessario leggere il file row per row, scrivere tutto tranne la row da eliminare in un file temporaneo e rinominare infine il file temporaneo.

 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; } 

beh, la risposta più semplice è non farlo con PHP. Seriamente, sed avrebbe funzionato molto meglio per questo perché l'integer file non sarebbe mai stato in memory. Dai un'occhiata a questi oneliner , ma in sostanza:

 sed '1d' filename 

So che le chiamate di sistema sono disapprovate, ma penso che questo potrebbe essere un caso in cui uno è giustificato.

Il metodo file () legge un integer file in un arrays, tutto in una volta. Immagino che questo sia where le cose esplodono. Probabilmente vorrai avere un secondo handle fopen () per il tuo file di input in modo da poter leggere una row alla volta.

Se il tuo requisito è quello di gestire questa attività con PHP, va bene. Ma questo tipo di cose è probabilmente meglio lasciato a qualcosa come awk