2009-12-07 12 views
41

C'è un modo per farlo:È possibile impedire a StreamReader di smaltire il flusso sottostante?

this.logFile = File.Open("what_r_u_doing.log", FileMode.OpenOrCreate, FileAccess.ReadWrite); 

using(var sr = new StreamReader(this.logFile)) 
{ 
    // Read the data in 
} 

// ... later on in the class ... 

this.logFile = File.Open("what_r_u_doing.log", FileMode.OpenOrCreate, FileAccess.ReadWrite); 

using(var sw = new StreamWriter(this.logFile)) 
{ 
    // Write additional data out... 
} 

senza dover aprire il file due volte?

Non riesco a far sì che lo StreamReader non disponga il mio stream. Non voglio lasciarlo andare fuori ambito. Quindi il garbage collector chiamerà infine il Dispose, uccidendo il flusso.

risposta

41

Non voglio lasciarlo andare fuori ambito. Quindi il garbage collector chiamerà infine il Dispose, uccidendo il flusso.

Garbage collector chiamerà la Finalize metodo (destructor), non il metodo Dispose. Il finalizzatore chiamerà il numero Dispose(false) che sarà non dispose il flusso sottostante. Dovresti essere a posto lasciando lo StreamReader fuori campo se hai bisogno di utilizzare direttamente il flusso sottostante. Assicurati di disporre manualmente del flusso sottostante quando è appropriato.

0

Chiudi te stesso in una clausola try/finally quando hai finito con esso.

var sr = new StreamReader(); 
try { 
    //...code that uses sr 
    //....etc 
} 
finally 
{ 
    sr.Close(); 
} 
2

Basta rimuovere il blocco di utilizzo. Non devi Dispose() StreamReader se non vuoi fare Dispose() lo stream, credo.

+3

Ma non c'è la possibilità che in futuro 'StreamReader' sarebbe essere modificato per tenere alcune risorse non gestito, avviare l'attuazione di un finalizzatore, e poi quando si va fuori portata in modo casuale chiudere il flusso di quando il garbage collector lo mette a punto?O dovremmo * supporre * assumere che, poiché ciò non accade ora, non lo sarà mai? – binki

15

è possibile utilizzare la classe NonClosingStreamWrapper da Jon Skeet di MiscUtil library, serve esattamente questo scopo

3

è possibile creare una nuova classe che eredita da StreamReader e sovrascrivere il metodo Close; all'interno del tuo metodo Close, chiama Dispose (false), che, come sottolineato da Mehrdad, non chiude il flusso. Lo stesso vale per StreamWriter, ovviamente.

Tuttavia, sembra che una soluzione migliore sarebbe semplicemente quella di mantenere le istanze StreamReader e StreamWriter per tutto il tempo necessario. Se stai già pianificando di mantenere aperto il flusso, potresti anche tenere aperti StreamReader e StreamWriter. Se si utilizza StreamWriter.Flush e Stream.Seek correttamente, si dovrebbe essere in grado di farlo funzionare anche quando si esegue sia la lettura che la scrittura.

59

.NET 4.5 potrà finalmente risolvere questo problema con un nuovo costruttori su StreamReader e StreamWriter che prendono un parametro leaveOpen:

StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) 

StreamWriter(Stream stream, System.Text.Encoding encoding, int bufferSize, bool leaveOpen) 
+16

Il problema con questo è che mi costringe a capire quale codifica deve passare per far sì che lo StreamReader si comporti nello stesso modo in cui lo ha fatto quando l'ho aperto usando il costruttore 'StreamReader (Stream)'. Quindi sto ancora utilizzando il "non dispongare e sperare che nessuno dei miei colleghi" corregga "il metodo inserendo l'approccio di StreamReader in un blocco" :( – phoog

+12

@phoog: (recuperando nella mia casella di posta) - MSDN dovrebbe elencare i valori predefiniti per sovraccarichi di tipo forwarding, ad esempio 'StreamReader (Stream)' dice "Questo costruttore inizializza la codifica in UTF8Encoding, la proprietà BaseStream utilizzando il parametro stream e la dimensione del buffer interno a 1024 byte." –

+4

@SimonBuchan Ma non dovrei è necessario codificare questi valori predefiniti nel mio programma. Il costruttore 'StreamReader()' avrebbe dovuto essere modificato per prendere un parametro di classe in stile options, come il funzionamento di 'XmlReaderSettings'. Quindi i valori predefiniti possono essere gestiti dal framework e dai nuovi parametri aggiunti in un modo non ABI-breaking e non hardbaked – binki

1

Utilizzare un altro overload del costruttore dove si può specifu un parametro "leaveOpen" a "true"

0

io uso sempre qualcosa di simile: (si usa anche l'argomento leaveOpen)

public static class StreamreaderExtensions 
{ 
    public static StreamReader WrapInNonClosingStreamReader(this Stream file) => new StreamReader(file, Encoding.UTF8, true, 1024, true); 
} 

Usage:

using (var reader = file.WrapInNonClosingStreamReader()) 
{ 
    .... 
} 
Problemi correlati