2012-04-30 19 views
7

Ho un file da 4 GB che voglio eseguire una ricerca e sostituzione basata su byte. Ho scritto un semplice programma per farlo ma ci vuole troppo tempo (90 minuti +) per fare solo una ricerca e sostituzione. Alcuni editor esadecimali che ho provato possono eseguire l'operazione in meno di 3 minuti e non caricare l'intero file di destinazione in memoria. Qualcuno conosce un metodo in cui posso realizzare la stessa cosa? Ecco il mio codice corrente:Elaborazione di file enormi in C#

public int ReplaceBytes(string File, byte[] Find, byte[] Replace) 
    { 
     var Stream = new FileStream(File, FileMode.Open, FileAccess.ReadWrite); 
     int FindPoint = 0; 
     int Results = 0; 
     for (long i = 0; i < Stream.Length; i++) 
     { 
      if (Find[FindPoint] == Stream.ReadByte()) 
      { 
       FindPoint++; 
       if (FindPoint > Find.Length - 1) 
       { 
        Results++; 
        FindPoint = 0; 
        Stream.Seek(-Find.Length, SeekOrigin.Current); 
        Stream.Write(Replace, 0, Replace.Length); 
       } 
      } 
      else 
      { 
       FindPoint = 0; 
      } 
     } 
     Stream.Close(); 
     return Results; 
    } 

Trova e Sostituisci sono relativamente piccoli rispetto al 4Gb "File" a proposito. Posso facilmente capire perché il mio algoritmo è lento, ma non sono sicuro di come potrei farlo meglio.

+8

Prima di tutto, leggere più di 1 byte alla volta. – SLaks

+0

http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm – SLaks

risposta

3

Parte del problema potrebbe essere la lettura del flusso un byte alla volta. Prova a leggere pezzi più grandi e fai una sostituzione su quelli. Vorrei iniziare con circa 8kb e quindi testare con pezzi più grandi o più piccoli per vedere quale ti offre le migliori prestazioni.

2

Invece di leggere file di byte per byte leggerla buffer:

buffer = new byte[bufferSize];    
currentPos = 0; 
length = (int)Stream .Length; 
while ((count = Stream.Read(buffer, currentPos, bufferSize)) > 0) 
{ 
    currentPos += count; 
    .... 
} 
+0

Bella risposta !!! Grazie. – hsalimi

1

altro, modo più semplice di leggere più di un byte alla volta:

var Stream = new BufferedStream(new FileStream(File, FileMode.Open, FileAccess.ReadWrite)); 

Combinando questo con l'esempio di Saeed Amiri di come leggere in un buffer, e uno dei migliori algoritmi di ricerca/sostituzione binari dovrebbe darti risultati migliori.

3

Ci sono un sacco di algoritmi migliori per la ricerca di una stringa in una stringa (che è fondamentalmente quello che state facendo)

cominciare da qui:

http://en.wikipedia.org/wiki/String_searching_algorithm

Il succo di loro è che si può saltare un sacco di byte analizzando la sottostringa. Ecco un semplice esempio

File 4GB inizia con: ABCDEFGHIJKLMNOP

tuo sottostringa è: NOP

  1. È saltare la lunghezza della stringa-1 e controllo contro l'ultimo byte, in modo confronta C a P
  2. Non corrisponde, quindi la sottostringa non è i primi 3 byte
  3. Inoltre, C non è nella sottostringa in tutto, in modo da poter passare altri 3 byte (len di sottostringa)
  4. Confronta F a P, non corrisponde, F non è in sottostringa, saltare 3
  5. Confronta I a P, ecc, ecc

Se corrisponde, andare indietro. Se il carattere non corrisponde, ma si trova nella sottostringa, è necessario eseguire ulteriori confronti a quel punto (leggere il collegamento per i dettagli)

1

Si dovrebbe provare a utilizzare memory-mapped files. C# li supporta iniziando con la versione 4.0.

Un file mappato in memoria contiene il contenuto di un file nella memoria virtuale.

I file persistenti sono file mappati in memoria associati a un file di origine su un disco. Quando l'ultimo processo ha finito di lavorare con il file, i dati vengono salvati sul file sorgente sul disco. Questi file mappati in memoria sono adatti per lavorare con file sorgente estremamente grandi.

+0

qualsiasi campione "reale" con codice sorgente completo? – Kiquenet