Estoy escribiendo un código:
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(gzipOutputStream));
¿Necesito cerrar cada transmisión o escritor como el siguiente?
gzipOutputStream.close();
bw.close();
outputStream.close();
¿O solo estará bien cerrar la última transmisión?
bw.close();
java
file-io
outputstream
writer
Adon Smith
fuente
fuente
BufferedWriter
es posible que deba escribir datos almacenados en la secuencia subyacente, que en su ejemplo ya está cerrada. Evitar estos problemas es otra ventaja de los enfoques de prueba con recursos que se muestran en las respuestas.Respuestas:
Asumiendo que todas las transmisiones se crean bien, sí, solo cerrar
bw
está bien con esas implementaciones de transmisiones ; Pero esa es una gran suposición.Usaría try-with-resources ( tutorial ) para que cualquier problema que construya las secuencias posteriores que arroje excepciones no deje las secuencias anteriores suspendidas, por lo que no tiene que confiar en que la implementación de la secuencia tenga la llamada para cerrar la corriente subyacente:
Tenga en cuenta que ya no llama
close
en absoluto.Nota importante : para que los recursos de prueba con los cierren, debe asignar las secuencias a las variables a medida que las abre, no puede usar el anidamiento. Si usa la anidación, una excepción durante la construcción de una de las secuencias posteriores (por ejemplo,
GZIPOutputStream
) dejará abierta cualquier secuencia construida por las llamadas anidadas dentro de ella. De JLS §14.20.3 :Tenga en cuenta la palabra "variables" (mi énfasis) .
Por ejemplo, no hagas esto:
... porque una excepción del
GZIPOutputStream(OutputStream)
constructor (que dice que puede lanzarIOException
y escribe un encabezado en la secuencia subyacente) dejaríaFileOutputStream
abierto. Dado que algunos recursos tienen constructores que pueden arrojar y otros no, es una buena costumbre enumerarlos por separado.Podemos verificar nuestra interpretación de esa sección JLS con este programa:
... que tiene la salida:
Tenga en cuenta que no hay llamadas
close
allí.Si arreglamos
main
:entonces recibimos las
close
llamadas apropiadas :(Sí, dos llamadas a
InnerMost#close
es correcta; una es deMiddle
, la otra es de prueba con recursos).fuente
java.io
, tampoco. Algunas corrientes, generalizando, algunos recursos , se lanzan desde los constructores. Por lo tanto, en mi opinión, asegurarse de que múltiples recursos se abran individualmente para que puedan cerrarse de manera confiable si un recurso posterior es solo un buen hábito. Puedes elegir no hacerlo si no estás de acuerdo, está bien.GZIPOutputStream
el constructor escribe un encabezado en la secuencia. Y para que pueda tirar. Así que ahora la posición es si creo que vale la pena molestarse en tratar de cerrar la transmisión después de escribir tiró. Sí: lo abrí, al menos debería intentar cerrarlo.Puede cerrar la secuencia más externa, de hecho, no necesita retener todas las secuencias envueltas y puede usar Java 7 try-with-resources.
Si se suscribe a YAGNI, o no lo va a necesitar, solo debe agregar el código que realmente necesita. No debería agregar código que imagina que podría necesitar, pero en realidad no hace nada útil.
Tome este ejemplo e imagine qué podría salir mal si no hiciera esto y cuál sería el impacto.
Comencemos con FileOutputStream que llama
open
a hacer todo el trabajo real.Si no se encuentra el archivo, no hay ningún recurso subyacente para cerrar, por lo que cerrarlo no hará ninguna diferencia. Si el archivo existe, debería lanzar una FileNotFoundException. Por lo tanto, no hay nada que ganar intentando cerrar el recurso solo desde esta línea.
La razón por la que necesita cerrar el archivo es cuando el archivo se abre con éxito, pero luego aparece un error.
Veamos la próxima transmisión
GZIPOutputStream
Hay un código que puede lanzar una excepción
Esto escribe el encabezado del archivo. Ahora sería muy inusual para usted poder abrir un archivo para escribir pero no poder escribir incluso 8 bytes, pero imaginemos que esto podría suceder y no cerramos el archivo después. ¿Qué le sucede a un archivo si no está cerrado?
No se obtienen escrituras sin vaciar, se descartan y, en este caso, no hay bytes escritos correctamente en la secuencia que, de todos modos, no están almacenados en este momento. Pero un archivo que no está cerrado no vive para siempre, en cambio FileOutputStream tiene
Si no cierra un archivo, se cierra de todos modos, solo que no inmediatamente (y como dije, los datos que quedan en un búfer se perderán de esta manera, pero no hay ninguno en este momento)
¿Cuál es la consecuencia de no cerrar el archivo de inmediato? En condiciones normales, puede perder algunos datos y quedarse sin descriptores de archivo. Pero si tiene un sistema donde puede crear archivos pero no puede escribirles nada, tiene un problema mayor. es decir, es difícil imaginar por qué intenta repetidamente crear este archivo a pesar del hecho de que está fallando.
Tanto OutputStreamWriter como BufferedWriter no lanzan IOException en sus constructores, por lo que no está claro qué problema causarían. En el caso de BufferedWriter, puede obtener un OutOfMemoryError. En este caso, activará inmediatamente un GC, que como hemos visto cerrará el archivo de todos modos.
fuente
GZIPOutputStream(OutputStream)
documentosIOException
y, mirando la fuente, en realidad escribe un encabezado. Entonces no es teórico, ese constructor puede tirar. Puede sentir que está bien dejar el subyacenteFileOutputStream
abierto después de escribirle. Yo no.Si se han instanciado todos los flujos, entonces cerrar solo el más externo está bien.
La documentación en la
Closeable
interfaz indica que el método de cierre:Los recursos del sistema de liberación incluyen el flujo de cierre.
También establece que:
Entonces, si los cierra explícitamente después, no pasará nada malo.
fuente
Prefiero usar la
try(...)
sintaxis (Java 7), por ejemplofuente
Estará bien si solo cierra la última secuencia; la llamada de cierre también se enviará a las secuencias subyacentes.
fuente
No, el nivel superior
Stream
oreader
garantizará que todas las transmisiones / lectores subyacentes estén cerradas.Verifique la implementación del
close()
método de su flujo de nivel superior.fuente
En Java 7, hay una función de prueba con recursos . No necesita cerrar explícitamente sus transmisiones, se encargará de eso.
fuente