2009-11-24 16 views
8

Si uso un FileStream para crear un StreamReader, ¿StreamReader se cerrará cuando cierro el FileStream o tendré que cerrar el StreamReader también?¿Cerrará FileStream el StreamReader?

public void ReadFile() 
{ 
    var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read); 
    var reader = new StreamReader(file); 

    try 
    { 
     txtFile.Text = reader.ReadToEnd(); 
    } 
    catch (Exception) 
    { 
     throw; 
    } 
    finally 
    { 
     file.Close(); 
    } 
} 
+0

posible duplicado de [¿Desechar el streamreader cierra la secuencia?] (Http://stackoverflow.com/questions/1065168/does-disposing-streamreader-close-the-stream) – mafu

Respuesta

7

Esencialmente sí. En realidad, no tiene que cerrar un StreamReader. Si lo haces, todo lo que hace es cerrar la secuencia subyacente.

@Bruno hace un buen punto al cerrar la envoltura más externa. Es una buena práctica cerrar la secuencia más externa y dejar que cierre las secuencias subyacentes para garantizar que todos los recursos se liberen correctamente.

De Reflector ...

public class StreamReader : TextReader 
{ 
    public override void Close() 
    { 
     this.Dispose(true); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     try 
     { 
      if ((this.Closable && disposing) && (this.stream != null)) 
      { 
       this.stream.Close(); 
      } 
     } 
     finally 
     { 
      if (this.Closable && (this.stream != null)) 
      { 
       this.stream = null; 
       this.encoding = null; 
       this.decoder = null; 
       this.byteBuffer = null; 
       this.charBuffer = null; 
       this.charPos = 0; 
       this.charLen = 0; 
       base.Dispose(disposing); 
      } 
     } 
    } 
} 
+0

IMO, esta es una muy mala práctica. En el futuro, los diseñadores de BCL pueden optar por agregar algunas estructuras adicionales que deban eliminarse ... –

+0

@bruno conde: usted mismo dijo que la parte superior del envoltorio debe desecharse. StreamReader es el contenedor principal para FileReader. ¿Dónde está el problema? – Kamarey

+0

@ Kamarey, el problema es que el OP solo está eliminando FileStream. –

0

No. Lo mejor que puede hacer es cerrarlas en orden inverso al que se hayan abierto.

6

No. En su lugar, debe cerrar el reader. En la práctica, esto podría no presentar ningún problema, pero el StreamReader podría agregar una sobrecarga que podría necesitar ser limpiada. Por lo tanto, siempre debe cerrar el contenedor más alto.

2

No es necesario cerrar StreamReader porque no posee ningún recurso no administrado. Cerrar FileStream es suficiente. Puede volver a escribir el código con using así:

public void ReadFile() 
{ 
    using (var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read)) 
    { 
     txtFile.Text = new StreamReader(file).ReadToEnd(); 
    } 
} 

En general, si usted está en duda, lo mejor es estar seguro y Desechar todos los objetos IDisposable cuando haya terminado de usarlos.

public void ReadFile() 
{ 
    using (FileStream file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read)) 
    { 
     using (StreamReader streamReader = new StreamReader(file)) 
     { 
      txtFile.Text = streamReader.ReadToEnd(); 
     } 
    } 
} 
+0

El "uso" que sé elimina del objeto, ¿esto asegura que la conexión también esté cerca? – norlando

+0

@norlando Sí lo hace, aunque en general depende de cada implementación de clase individual sobre lo que sucede en un desecho. En el caso de las transmisiones estándar, sigue los pasos lógicos de vaciar las memorias intermedias, cerrar la secuencia y deshacerse de cualquier objeto gestionado y no gestionado. –

6

También puedes, simplemente usar el método File.ReadAllText:

txtFile.Text = File.ReadAllText(@"c:\file.txt"); 
+0

¿Cómo funciona eso? ¿Simplemente abre una conexión, lee el archivo completo y luego cierra el archivo? – norlando

+0

Sí, hace exactamente eso. –

0

Me parece que la mejor manera de hacer esto en general sería que el FileStream cierre sólo a sí mismo. No tiene conocimiento implícito de nada que exista en una capa encima de sí mismo, por lo que es efectivamente un error que haga cualquier cosa que afecte esas capas superiores.

Dicho esto, las construcciones de nivel superior no deben suponer axiomáticamente nada sobre cualquier capa subyacente suministrado, así, o si lo hacen, deben hacerlo de forma explícita:

1) Si se crea de una flujo existente, entonces el constructo de nivel superior debería poder cerrarse INDEPENDIENTEMENTE del flujo subyacente (efectivamente solo descartando los recursos que asignó para su propio uso), o cerró INCLUYENDO el flujo subyacente. Estas deberían ser dos llamadas a función distintas, por ejemplo Close() y CloseSelf() (si esto se implementara de forma que sea compatible con el código existente).

2) Si no se creó a partir de una secuencia existente (es decir, el constructor tuvo que crear la secuencia subyacente), cerrar la construcción de nivel superior también obligará a la secuencia subyacente a cerrarse, dado que en ese caso la secuencia subyacente es una parte implícita de la construcción de nivel superior. En este caso, CloseSelf() simplemente llamaría a Close().

Parece un desperdicio implementar estas clases de la forma en que se hizo.Si planea usar el mismo archivo para (por ejemplo) entrada en serie y salida en serie, el sistema lo fuerza efectivamente a tratarlo como dos entidades distintas si desea obtener acceso a la funcionalidad de nivel superior de las clases descendientes. Su alternativa es apegarse a la construcción de nivel inferior e implementar la funcionalidad de nivel superior usted mismo, implementando de manera efectiva sus propias versiones especiales de clases descendientes que ya existen.

Si se hiciera como se describió anteriormente, la funcionalidad típica sería tan simple de implementar como ahora, pero para aplicaciones más sofisticadas se retendría la capacidad de colocar un solo candado en un archivo y reutilizarlo como se requiere cuando se requiere en lugar de tener que abandonar el bloqueo y todos los recursos asociados y luego reasignarlos instantáneamente de nuevo, agregando sobrecarga y fragmentación de memoria al sistema sin ningún motivo válido.

En las condiciones existentes, sin embargo, lo correcto es claro. No se puede suponer que FileStream sepa nada sobre ningún objeto del que forme parte, por lo que debe cerrar el constructo circundante más externo. Esto se aplica independientemente de si funciona o no de cualquier manera, como señalaron Bruno y otros, y por la razón que dieron - compatibilidad. La suposición es el bisabuelo de los errores más feos.

0

Un aspecto interesante es que el cierre de un StreamReader o escritor afectará el estado de lectura/escritura de la propiedad de FileStream. Esto parece significar que no puede usar un StreamReader y luego un StreamWriter usando la misma extensión de archivos.