2013-07-25 23 views
5

Ho un file piuttosto grande composto da diversi milioni di righe e vi è la necessità di controllare e rimuovere le righe danneggiate dal file.lettura e modifica di file di testo di grandi dimensioni 3-5 GB

Ho provato spudoratamente File.ReadAllLines ma non ha funzionato. Poi ho provato a eseguire lo streaming delle righe come di seguito la lettura dal file originale e la scrittura di uno nuovo. Mentre fa il lavoro, lo fa in diverse ore (5+). Ho letto sull'utilizzo di buffer che suona come l'unica opzione, ma come faccio a mantenere l'integrità della linea in questo modo?

Soluzione: StreamWriter spostato all'esterno. Invece di split, viene utilizzato il conteggio.

using (FileStream inputStream = File.OpenRead((localFileToProcess + ".txt"))) 
{ 
    using (StreamReader inputReader = new StreamReader(inputStream, System.Text.Encoding.GetEncoding(1254))) 
    { 
     using(StreamWriter writer=new StreamWriter(localFileToProcess,true,System.Text.Encoding.GetEncoding(1254))) 
     { 
      while (!inputReader.EndOfStream) 
      { 
      if ((tempLineValue = inputReader.ReadLine()).Count(c => c == ';') == 4) 
      { 
       writer.WriteLine(tempLineValue); 
      } 
      else 
       incrementCounter(); 
      } 
     } 
    } 
} 
+3

Nota che Split (';') assegna un array e crea 5 stringhe in memoria per ogni riga. Questo aggiunge lavoro per un garbage collector. Forse dovresti controllare che ci siano 4 punti e virgola nella tua linea? Inoltre ogni iterazione si sta creando/disponendo StreamWriter. Non è meglio crearne uno all'inizio e smaltirlo alla fine dell'operazione? – Artemix

+0

buon punto. Farò i cambiamenti. – mechanicum

+0

che ne dici di leggere un batch in un generatore di stringhe, elaborare e quindi scrivere tutto in una volta? – bhs

risposta

1

Penso che la parte più lenta nel codice originale sia stata la creazione/eliminazione di StreamWriter. Su ogni Dispose, StreamWriter doveva scaricare tutti i dati non scritti sul disco, chiudere gli handle dei file, ecc. Su sistemi operativi aperti dovevano controllare le autorizzazioni di sicurezza, i blocchi correnti e fare anche molte altre cose.

Quando si è iniziato a utilizzare solo uno StreamWriter, il suo buffer di scrittura interno ha iniziato a lavorare scrivendo i dati sul disco in blocchi di grandi dimensioni. Oltre a saltare il file di chiusura/apertura per la scrittura, ciò consente di risparmiare un sacco di tempo. Disk I/O è in genere la parte più lenta dell'applicazione.

Split (';') ha anche avuto un impatto sulla velocità, ma penso che sia meno significativo. In ogni caso, le operazioni con le stringhe devono essere eseguite con attenzione in C#, perché le stringhe sono immutabili e possono creare un sacco di spazzatura in memoria. Quindi, se è possibile verificare la presenza di 4 punti e virgola, è sempre preferibile chiamare Split (';') che assegna un array e (nel tuo caso) crea 5 stringhe in memoria per ogni riga. Quando vengono eseguite molte operazioni con le stringhe utilizzando stringhe immutabili, le prestazioni delle applicazioni possono essere notevolmente compromesse anche senza I/O del disco.

Per quanto riguarda l'uso di StringBuilder nel tuo caso, non penso che sia di grande aiuto, perché StreamWriter ha già il buffering integrato.