2009-12-07 18 views
41

¿Hay una manera de hacer esto:¿Puedes evitar que StreamReader elimine la transmisión subyacente?

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

sin tener que abrir el archivo dos veces?

Parece que no puedo hacer que StreamReader no elimine mi transmisión. No quiero simplemente dejarlo fuera del alcance, tampoco. Entonces, el recolector de basura eventualmente llamará al Dispose, matando a la corriente.

Respuesta

41

No quiero simplemente dejarlo fuera de alcance, tampoco. Entonces, el recolector de basura eventualmente llamará al Dispose, matando a la corriente.

colector de basura llamará al método Finalize (destructor), no el método Dispose. El finalizador llamará al Dispose(false) que marcará y no para eliminar el flujo subyacente. Debería estar bien dejando el StreamReader fuera del alcance si necesita usar el flujo subyacente directamente. Solo asegúrese de desechar la transmisión subyacente manualmente cuando sea apropiado.

0

Ciérrelo usted mismo en una cláusula try/finally cuando haya terminado con él.

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

Simplemente quite el bloque de uso. No es necesario que deseche() el StreamReader si no desea Dispose() la transmisión, creo.

+3

Pero no es allí la posibilidad de que en el futuro 'StreamReader' sería modificado para contener algún recurso no administrado, empezar a aplicar un finalizador, y luego cuando se va fuera de alcance al azar cerrar su torrente cuando el recolector de basura finaliza?¿O debemos * suponer * que, dado que esto no sucede ahora, nunca lo hará? – binki

15

usted podría utilizar la clase NonClosingStreamWrapper de Jon Skeet de MiscUtil library, sirve exactamente ese propósito

3

Se puede crear una nueva clase que hereda de StreamReader y anular el método Close; dentro de su método Close, llame a Dispose (false), que como señaló Mehrdad, no cierra la transmisión. Lo mismo se aplica a StreamWriter, por supuesto.

Sin embargo, parece que una mejor solución sería simplemente aferrarse a las instancias StreamReader y StreamWriter siempre que las necesite. Si ya planea mantener la transmisión abierta, también podría mantener abiertos StreamReader y StreamWriter. Si usa StreamWriter.Flush y Stream.Seek correctamente, debería poder hacer que esto funcione incluso al leer y escribir.

59

.NET 4.5 finalmente solucionar este problema con una nueva constructores en StreamReader y StreamWriter que tienen un parámetro LeaveOpen:

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

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

El problema con esto es que me obliga a descubrir qué codificación debe pasar para que el StreamReader se comporte de la misma manera que cuando lo abrí usando el constructor 'StreamReader (Stream)'. Por lo tanto, sigo utilizando el término "no desechar y espero que ninguno de mis colegas 'corrija' el método colocando el StreamReader en un bloque de uso ':( – phoog

+12

@phoog: (poniéndome al día en mi bandeja de entrada) - MSDN debería listar los valores predeterminados para sobrecargas de estilo de reenvío, por ejemplo 'StreamReader (Stream)' dice "Este constructor inicializa la codificación en UTF8Encoding, la propiedad BaseStream utilizando el parámetro de flujo y el tamaño interno del búfer en 1024 bytes." –

+4

@SimonBuchan Pero no debería tengo que codificar estos valores predeterminados en mi programa. El constructor 'StreamReader()' debería haberse alterado para tomar un parámetro de clase de estilo de opciones, como por ejemplo '' XmlReaderSettings'. Luego los valores predeterminados pueden ser gestionados por el framework y se agregarán nuevos parámetros en una forma no ABI y no hardbaked. – binki

1

Uso otra sobrecarga del constructor donde se puede specifu un parámetro "LeaveOpen" a "true"

0

siempre utilizo algo como esto: (que también utiliza el argumento leaveOpen)

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

Uso:

using (var reader = file.WrapInNonClosingStreamReader()) 
{ 
    .... 
} 
Cuestiones relacionadas