2011-09-06 14 views
19

Al momento sto scrivendo uno script di importazione per un file CSV molto grande. Il problema è che la maggior parte delle volte si interrompe dopo un po 'a causa di un timeout o genera un errore di memoria.Elabora file csv molto grande senza timeout e errore di memoria

La mia idea era ora di analizzare il file CSV in "100 righe" e dopo 100 righe richiamare automaticamente lo script. Ho cercato di ottenere questo risultato con header (posizione ...) e passare la riga corrente con get ma non ha funzionato come voglio.

C'è un modo migliore per questo o qualcuno ha un'idea di come eliminare l'errore di memoria e il timeout?

+2

Quanto grande è il file CSV? Devi importarlo in un database? –

+0

controlla la mia risposta su http://stackoverflow.com/a/22744300/2037323 che include anche alcuni confronti. –

risposta

44

Ho usato fgetcsv per leggere un csv di 120 MB in modalità stream-wise (è corretto l'inglese?). Questo si legge riga per riga e poi ho inserito ogni riga in un database. In questo modo viene trattenuta una sola riga in memoria su ciascuna iterazione. La sceneggiatura aveva ancora bisogno di 20 minuti. correre. Forse la prossima volta provo Python ... Non provare a caricare un enorme file csv in un array, che consumerebbe molta memoria.

// WDI_GDF_Data.csv (120.4MB) are the World Bank collection of development indicators: 
// http://data.worldbank.org/data-catalog/world-development-indicators 
if(($handle = fopen('WDI_GDF_Data.csv', 'r')) !== false) 
{ 
    // get the first row, which contains the column-titles (if necessary) 
    $header = fgetcsv($handle); 

    // loop through the file line-by-line 
    while(($data = fgetcsv($handle)) !== false) 
    { 
     // resort/rewrite data and insert into DB here 
     // try to use conditions sparingly here, as those will cause slow-performance 

     // I don't know if this is really necessary, but it couldn't harm; 
     // see also: http://php.net/manual/en/features.gc.php 
     unset($data); 
    } 
    fclose($handle); 
} 
12

Se non ti interessa il tempo necessario e la quantità di memoria necessaria, puoi semplicemente aumentare i valori per questo script. Basta aggiungere le seguenti righe all'inizio dello script:

ini_set('memory_limit', '512M'); 
ini_set('max_execution_time', '180'); 

Con la funzione memory_get_usage() si può scoprire la quantità di memoria lo script ha bisogno di trovare un buon valore per il memory_limit.

Si potrebbe anche voler dare un'occhiata a fgets() che consente di leggere un file riga per riga. Non sono sicuro che ciò richieda meno memoria, ma penso davvero che funzionerà. Ma anche in questo caso devi aumentare max_execution_time a un valore più alto.

+1

Questo è ovviamente un buon approccio se si sa che il file ha sempre le stesse dimensioni. –

+3

Se sai che non è più grande di una dimensione particolare, funziona anche. – 2ndkauboy

-2

Oh. Basta fare questo script chiamato CLI, non tramite una stupida interfaccia web. Quindi, nessun limite di tempo di esecuzione influirà su di esso.
E non mantenere i risultati analizzati per sempre, ma scriverli immediatamente - così, non sarà influenzato nemmeno dal limite di memoria.

12

trovo il caricamento del file e l'inserimento utilizzando MySQL LOAD DATA LOCAL richiesta una soluzione veloce per esempio:

$sql = "LOAD DATA LOCAL INFILE '/path/to/file.csv' 
     REPLACE INTO TABLE table_name FIELDS TERMINATED BY ',' 
     ENCLOSED BY '\"' LINES TERMINATED BY '\r\n' IGNORE 1 LINES"; 
    $result = $mysqli->query($sql); 
+0

Wow Sono passato da 5 minuti + all'importazione di 64000 record csv a meno di 5 secondi. È fantastico! – Iznogood

Problemi correlati