2009-12-07 10 views
41

Gibt es eine Möglichkeit, dies zu tun:Können Sie einen StreamReader davon abhalten, den zugrunde liegenden Stream zu entsorgen?

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... 
} 

Ohne die Datei zweimal zu öffnen?

Ich kann nicht scheinen, den StreamReader nicht-dispose meinen Strom zu machen. Ich will es auch nicht einfach außer Reichweite lassen. Dann ruft der Garbage Collector schließlich den Dispose auf und tötet den Stream.

Antwort

41

Ich will es nicht einfach aus dem Rahmen gehen lassen. Dann ruft der Garbage Collector schließlich den Dispose auf und tötet den Stream.

Garbage Collector ruft die Methode Finalize (destructor), nicht die Dispose Methode. Der Finalizer ruft Dispose(false) auf, der nicht den zugrunde liegenden Stream entsorgt. Sie sollten OK sein, indem Sie den Bereich StreamReader außerhalb des Gültigkeitsbereichs verlassen, wenn Sie den zugrunde liegenden Stream direkt verwenden müssen. Stellen Sie nur sicher, dass Sie den zugrunde liegenden Stream manuell freigeben, wenn es angemessen ist.

0

Schließen Sie es in einer try/finally Klausel, wenn Sie damit fertig sind.

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

Entfernen Sie einfach den using-Block. Sie müssen den StreamReader nicht dispose(), wenn Sie den Stream nicht mit Dispose() betreiben wollen, denke ich.

+3

Aber gibt es nicht die Möglichkeit, dass in Zukunft 'StreamReader' modifiziert werden würde einige nicht verwaltete Ressource zu halten, starten Sie eine Finalizerthread Implementierung und dann, wenn außerhalb des Gültigkeitsbereiches zufällig in der Nähe Stream gehen wenn der Müllsammler es fertigstellt?Oder sollen wir annehmen, dass dies nicht geschieht, weil das jetzt nicht geschieht? – binki

15

Sie konnten die NonClosingStreamWrapper Klasse von Jon Skeet verwenden MiscUtil library, es dient genau diesem Zweck

3

Sie könnten eine neue Klasse erstellen, die von Stream erbt und die Close-Methode außer Kraft setzen; Rufen Sie in Ihrer Close-Methode Dispose (false) auf, was, wie Mehrdad sagte, den Stream nicht schließt. Gleiches gilt natürlich für StreamWriter.

Es scheint jedoch, als wäre eine bessere Lösung einfach, die StreamReader und StreamWriter-Instanzen zu halten, solange Sie sie benötigen. Wenn Sie bereits planen, den Stream geöffnet zu lassen, können Sie auch StreamReader und StreamWriter öffnen. Wenn Sie StreamWriter.Flush und Stream.Seek korrekt verwenden, sollten Sie in der Lage sein, dies auch beim Lesen und Schreiben zu erreichen.

59

.NET 4.5 wird dieses Problem endlich mit einem neuen Konstrukteure auf Stream und Stream beheben, die einen Parameter nehmen Leaveopen:

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

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

Das Problem dabei ist, dass es mich zwingt herauszufinden, welche Codierung übergeben werden soll, damit sich der StreamReader genauso verhält wie beim Öffnen mit dem 'StreamReader (Stream)' -Konstruktor. So benutze ich immer noch die "nicht entsorgen und hoffen, dass keiner meiner Kollegen 'die Methode korrigieren, indem Sie den StreamReader in einen using Block" -Ansatz setzen :( – phoog

+12

@phoog: (holt in meinem Posteingang) - MSDN sollte Standardwerte auflisten Bei Überladungen im Forwarding-Stil, zum Beispiel 'StreamReader (Stream)' sagt "Dieser Konstruktor initialisiert die Kodierung zu UTF8Encoding, die BaseStream-Eigenschaft mit dem stream-Parameter und die interne Puffergröße zu 1024 Bytes." –

+4

@SimonBuchan Aber ich sollte nicht Ich muss diese Standardwerte in meinem Programm fest codieren.Der 'StreamReader()' -Konstruktor sollte so geändert worden sein, dass er einen Klassenparameter wie bei 'XmlReaderSettings' verwendet. Dann können die Standardwerte vom Framework verwaltet und neue Parameter hinzugefügt werden eine nicht-ABI-brechende und nicht-hardbaked Art. – binki

1

Verwenden Sie eine andere Konstruktor Überlastung, wo Sie einen „Leaveopen“ Parameter specifu kann auf „true“

0

ich immer so etwas wie folgt verwenden: (es nutzt auch die leaveOpen Argument)

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

:

using (var reader = file.WrapInNonClosingStreamReader()) 
{ 
    .... 
} 
Verwandte Themen