2013-04-24 10 views
6

Devo scrivere migliaia di righe generate dinamicamente in un file di testo. Ho due scelte, che consuma meno risorse ed è più veloce dell'altra?Cosa consuma meno risorse ed è più veloce File.AppendText o File.WriteAllText che memorizza prima in StringBuilder?

A. Utilizzo StringBuilder e File.WriteAllText

StringBuilder sb = new StringBuilder(); 
foreach(Data dataItem in Datas) 
{ 
sb.AppendLine(String.Format("{0}, {1}-{2}",dataItem .Property1,dataItem .Property2,dataItem .Property3)); 
} 
File.WriteAllText("C:\\example.txt", sb.ToString(), new UTF8Encoding(false)); 

B. Utilizzo File.AppendText

using(StreamWriter sw = File.AppendText("C:\\example.txt")){ 
           foreach (Data dataItem in Datas) 
           { 
            sw.WriteLine(String.Format("{0}, {1}-{2}",dataItem .Property1,dataItem .Property2,dataItem .Property3)); 
           } 
          } 
+5

http://ericlippert.com/2012/12/17/performance-rant/ –

+0

Ho bisogno di fare questa operazione il più velocemente possibile, perché implica il networking e la scrittura del database. E ho alcuni colli di bottiglia legati, quindi sto facendo questa domanda perché ho bisogno, non perché non sono a conoscenza dell'articolo che hai collegato. –

+1

Non sono sicuro che la velocità dovrebbe essere la vostra preoccupazione principale qui. L'utilizzo della memoria è chiaramente quello che dovrebbe guidare la tua decisione. Se i dati sono sempre piccoli, è sufficiente eseguire alcuni test per determinare quale sia più veloce. – juharr

risposta

14

La prima versione, che inserisce tutto in un StringBuilder e quindi lo scrive, consumerà più memoria. Se il testo è molto grande, hai il potenziale di esaurire la memoria. Ha il potenziale per essere più veloce, ma potrebbe anche essere più lento.

La seconda opzione utilizzerà molta meno memoria (in pratica, solo il buffer StreamWriter) e funzionerà molto bene. Consiglierei questa opzione. Funziona bene - forse meglio del primo metodo - e non ha lo stesso potenziale per esaurire la memoria.

È possibile accelerarlo parecchio aumentando la dimensione del buffer di uscita. Piuttosto che

File.AppendText("filename") 

Creare il flusso con:

const int BufferSize = 65536; // 64 Kilobytes 
StreamWriter sw = new StreamWriter("filename", true, Encoding.UTF8, BufferSize); 

Una dimensione del buffer di 64K offre prestazioni molto migliori rispetto alla dimensione del buffer di default 4K. È possibile aumentare le dimensioni, ma ho scoperto che più di 64 KB offre un guadagno minimo di prestazioni e in alcuni sistemi è possibile ridurre le prestazioni dello .

+0

Questa dimensione del buffer è difficile da prevedere, perché non conosco mai la quantità di linee e dati che richiede. Penso tra 2k e 4k. Ho avuto il rischio di OutOfMemoryException se arbitrario sceglierò un buffer minore rispetto a quello di cui ho bisogno. –

+0

@ AlbertoLeón: No, selezionare una dimensione del buffer troppo piccola non ti darà un'eccezione di memoria insufficiente. Questo è solo un buffer temporaneo utilizzato da 'StreamWriter' per impedirgli di chiamare la funzione' Write' di Windows per ogni carattere. Memorizza i dati e li scrive in blocchi. Non riceverai un errore se proverai a scrivere un blocco più grande del buffer. –

+0

fantastico! Quindi penso che la tua soluzione migliori il mio secondo approccio, mi piace. –

7

Si ha almeno un altra scelta, utilizzando File.AppendAllLines()

var data = from item in Datas 
      select string.Format("{0}, {1}-{2}", item.Property1, item.Property2, item.Property3); 

File.AppendAllLines("Filename", data, new UTF8Encoding(false)); 

Questo teoricamente utilizzerà meno memoria rispetto al primo approccio in quanto solo una riga alla volta verrà memorizzata nella memoria.

Probabilmente sarà quasi esattamente lo stesso del tuo secondo approccio. Ti sto solo mostrando una terza alternativa. L'unico vantaggio di questo è che puoi nutrirlo con una sequenza Linq, che a volte può essere utile.

La velocità di I/O impallidire qualsiasi altra considerazione, così si dovrebbe concentrarsi su riducendo al minimo l'utilizzo della memoria, come juharr osservato in precedenza (e considerando anche i pericoli di ottimizzazione prematura, ovviamente!)

Questo significa che utilizzando il secondo approccio, o quello che ho messo qui.

+0

Penso che mi piaccia questo il meglio. Buona risposta. –

+0

Ho sorpreso perché il numero ridotto di linee. È più leggibile Ma cosa sono i dati var? Una serie di stringhe? –

+0

@ AlbertoLeón: 'data' è un' IEnumerable '. Dovrai leggere su LINQ per comprenderne le implicazioni. –