2010-01-29 6 views
8

Sto cercando di eseguire una sostituzione di stringa per l'intero file in PHP. Il mio file ha più di 100 MB, quindi devo andare linea per riga e non posso usare file_get_contents(). C'è una buona soluzione a questo?stringa di sostituzione in un file di grandi dimensioni con php

+2

È necessario utilizzare PHP? Se si ha accesso alla riga di comando, è possibile utilizzare il comando 'sed' per eseguire questa stessa funzione, probabilmente con un mal di testa molto inferiore. Se ha bisogno di essere automatizzato, puoi creare uno script di shell che gira su cron. –

+1

D'accordo, questo è qualcosa per la riga di comando, non per PHP. – Mike

risposta

10

Se non si richiede l'utilizzo di PHP, si consiglia vivamente di eseguire operazioni di questo tipo dalla riga di comando. È di gran lunga lo strumento migliore per il lavoro e molto più facile da usare.

In ogni caso, il comando sed è quello che state cercando:

sed s/search/replace oldfilename > newfilename 

Se avete bisogno della cassa-insensibilità:

sed -i s/search/replace oldfilename > newfilename 

Se avete bisogno di questo per eseguire in modo dinamico all'interno PHP, è possibile utilizzare passthru():

$output = passthru("sed s/$search/$replace $oldfilename > $newfilename"); 
+1

perché 'passthru()' e non 'exec()'? – Brian

+3

Entrambi funzionerebbero, ma usando il passthru, è possibile ottenere l'intero output. exec restituisce solo l'ultima riga dell'output. –

+0

non è così facile da usare passthru per chiamare sed, vedere la mia risposta per i dettagli. –

1

Farlo poche righe alla volta, scaricare la variabile, ottenere le righe successive.

$fh = fopen("bigfile.txt", "flags"); 
$num = 0; 
$length = 300; 
$filesize = filesize("bigfile.txt"); 

while($num < $filesize) 
{ 
    $contents = fread($fh, $length); 
    // .. do stuff ... 
    $num = $num+$length; 
    fseek($fh, $num); 
} 

fclose($fh); 

Si desidera assicurarsi che sia corretto (non testato). Vedi la biblioteca su PHP Documentation.

La parte difficile sta per essere scritta sul file. La prima idea che mi viene in mente è sostituire la stringa, scrivere il nuovo contenuto in un altro file e alla fine eliminare il vecchio file e sostituirlo con quello nuovo.

+0

sì, è giusto ... lo streaming di un povero.Che efficacemente avrebbe funzionato se lo avessi fatto sulla riga di comando: cat file | sed 's/replace/something/g'> output.file – mlathe

+0

Avrei eseguito uno script php che ha chiamato la funzione riga di comando - quindi stampato il file di output :) – Dirk

+1

Questo metodo ha un problema se la stringa che stai cercando sostituire è più lungo di un singolo carattere. È abbastanza probabile che la stringa possa estendersi su più blocchi di dati, causando la possibilità di saltare la sostituzione. – bish

6

Qui si va:

function replace_file($path, $string, $replace) 
{ 
    set_time_limit(0); 

    if (is_file($path) === true) 
    { 
     $file = fopen($path, 'r'); 
     $temp = tempnam('./', 'tmp'); 

     if (is_resource($file) === true) 
     { 
      while (feof($file) === false) 
      { 
       file_put_contents($temp, str_replace($string, $replace, fgets($file)), FILE_APPEND); 
      } 

      fclose($file); 
     } 

     unlink($path); 
    } 

    return rename($temp, $path); 
} 

chiamare in questo modo:

replace_file('/path/to/fruits.txt', 'apples', 'oranges'); 
+0

Immagino solo che tu abbia questa funzione in giro? –

+1

@ Chacha102: No, l'ho appena codificato. Perché? –

+5

Era una specie di barzelletta. Non so perché sarebbe stato divertente. Lo darò al nostro JDT (Joke Development Team) e ti ricontatterò tra 6 e 8 settimane. –

1

qualcosa di simile?

$infile="file"; 
$outfile="temp"; 
$f = fopen($infile,"r"); 
$o = fopen($outfile,"a"); 
$pattern="pattern"; 
$replace="replace"; 
if($f){ 
    while(!feof($f)){ 
     $line = fgets($f,4096); 
     if (strpos($pattern,"$line") !==FALSE){ 
      $line=str_replace($pattern,$replace,$line); 
     } 
     fwrite($o,$line); 
    } 
} 
fclose($f); 
fclose($o); 
rename($outfile,$infile); 
1

Avrei usato "sed" in un modo più esplicito, quindi sei meno dipendente dal tuo sistema.

$output = passthru("sed -e 's/$search/$replace/g' $oldfilename > $newfilename"); 
2

Se non è possibile utilizzare direttamente sed da linea di comando, perché è un compito dinamico ed è necessario chiamare da php è difficile ottenere il giusto sintassi: si deve fuggire in modi diversi nella ricerca e sostituzione stringhe questi personaggi

'/$ . * [ ] \^& 

la seguente funzione di ricerca e sostituzione di una stringa in un file senza interpretare la stringa cercata come un'espressione regolare. Quindi, se lo si desidera, è possibile cercare la stringa ". *" E sostituirla con "$".

/** 
* str_replace_with_sed($search, $replace, $file_in, $file_out=null) 
* 
* Search for the fixed string `$search` inside the file `$file_in` 
* and replace it with `$replace`. The replace occurs in-place unless 
* `$file_out` is defined: in that case the resulting file is written 
* into `$file_out` 
* 
* Return: sed return status (0 means success, any other integer failure) 
*/ 
function str_replace_with_sed($search, $replace, $file_in, $file_out=null) 
{ 
    $cmd_opts = ''; 
    if (! $file_out) 
    { 
     // replace inline in $file_in 
     $cmd_opts .= ' -i'; 
    } 

    // We will use Basic Regular Expressions (BRE). This means that in the 
    // search pattern we must escape 
    // $.*[\]^ 
    // 
    // The replacement string must have these characters escaped 
    // \ & 
    // 
    // In both cases we must escape the separator character too (usually /) 
    // 
    // Since we run the command trough the shell we We must escape the string 
    // too (yai!). We're delimiting the string with single quotes (') and we'll 
    // escape them with '\'' (close string, write a single quote, reopen string)  

    // Replace all the backslashes as first thing. If we do it in the following 
    // batch replace we would end up with bogus results 
    $search_pattern = str_replace('\\', '\\\\', $search); 

    $search_pattern = str_replace(array('$', '.', '*', '[', ']', '^'), 
            array('\\$', '\\.', '\\*', '\\[', '\\]', '\\^'), 
            $search_pattern); 

    $replace_string = str_replace(array('\\', '&'), 
            array('\\\\', '\\&'), 
            $replace); 

    $output_suffix = $file_out ? " > '$file_out' " : ''; 
    $cmd = sprintf("sed ".$cmd_opts." -e 's/%s/%s/g' \"%s\" ".$output_suffix, 
        str_replace('/','\\/', # escape the regexp separator 
         str_replace("'", "'\''", $search_pattern) // sh string escape 
        ), 
        str_replace('/','\\/', # escape the regexp separator 
         str_replace("'", "'\''", $replace_string) // sh string escape 
        ), 
        $file_in 
       ); 

    passthru($cmd, $status); 

    return $status; 
} 
Problemi correlati