semaforos resueltos productor lectores lector hilos escritores escritor ejemplos consumidor java java-io

resueltos - Forma correcta de cerrar secuencias anidadas y escritores en Java



lectores escritores semaforos java (10)

Además, no tiene que cerrar todas las secuencias anidadas

mira esto http://ckarthik17.blogspot.com/2011/02/closing-nested-streams.html

Esta pregunta ya tiene una respuesta aquí:

Nota: Esta pregunta y la mayoría de sus respuestas datan de antes del lanzamiento de Java 7. Java 7 proporciona la funcionalidad de administración automática de recursos para hacer esto fácilmente. Si está utilizando Java 7 o posterior, debe avanzar a la respuesta de Ross Johnson .

¿Cuál es considerada la mejor y más completa forma de cerrar secuencias anidadas en Java? Por ejemplo, considere la configuración:

FileOutputStream fos = new FileOutputStream(...) BufferedOS bos = new BufferedOS(fos); ObjectOutputStream oos = new ObjectOutputStream(bos);

Entiendo que la operación cercana necesita estar asegurada (probablemente mediante el uso de una cláusula finally). Lo que me pregunto es, ¿es necesario asegurarse explícitamente de que las secuencias anidadas estén cerradas, o sea suficiente para asegurarse de cerrar la secuencia externa (oos)?

Una cosa que noto, al menos tratando con este ejemplo específico, es que las transmisiones internas solo parecen arrojar FileNotFoundExceptions. Lo que parece implicar que técnicamente no hay necesidad de preocuparse por cerrarlos si fallan.

Esto es lo que escribió un colega:

Técnicamente, si se implementó correctamente, el cierre de la corriente más externa (oos) debería ser suficiente. Pero la implementación parece defectuosa.

Ejemplo: BufferedOutputStream hereda close () de FilterOutputStream, que lo define como:

155 public void close() throws IOException { 156 try { 157 flush(); 158 } catch (IOException ignored) { 159 } 160 out.close(); 161 }

Sin embargo, si flush () arroja una excepción de tiempo de ejecución por alguna razón, entonces nunca se invocará out.close (). Por lo tanto, parece "más seguro" (pero feo) preocuparse principalmente por el cierre de FOS, que es mantener el archivo abierto.

¿Cuál es considerado el mejor enfoque instantáneo cuando se necesita absolutamente estar seguro de cerrar transmisiones anidadas?

¿Y hay documentos oficiales de Java / Sun que se ocupen de esto con todo lujo de detalles?


Al cerrar transmisiones encadenadas, solo necesita cerrar la transmisión más externa. Cualquier error se propagará por la cadena y será atrapado.

Consulte Secuencias de E / S de Java para más detalles.

Para abordar la cuestión

Sin embargo, si flush () arroja una excepción de tiempo de ejecución por alguna razón, entonces nunca se invocará out.close ().

Esto no es correcto Después de atrapar e ignorar esa excepción, la ejecución se recuperará después del bloque catch y se out.close() la out.close() .

Su colega hace una buena observación sobre la Excepción de tiempo de ejecución . Si realmente necesita que se cierre la transmisión, siempre puede intentar cerrar cada uno individualmente, desde afuera hacia adentro, deteniéndose en la primera excepción.


El Java SE 7 try-with-resources no parece ser mencionado. Elimina la necesidad de cerrar explícitamente por completo, y me gusta bastante la idea.

Desafortunadamente, para Android, este dulce solo está disponible al usar Android Studio (creo) y apuntar a Kitkat y más .


El colega plantea un punto interesante, y hay motivos para discutir de cualquier manera.

Personalmente, ignoraría la RuntimeException , porque una excepción sin marcar significa un error en el programa. Si el programa es incorrecto, arréglalo. No puede "manejar" un programa malo en tiempo de ejecución.


En la era de Java 7, try-with-resources es sin duda el camino a seguir. Como se menciona en varias respuestas anteriores, la solicitud de cierre se propaga desde la secuencia más externa a la secuencia más interna. Entonces, un solo cierre es todo lo que se requiere.

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) { // do something with ois }

Sin embargo, hay un problema con este patrón. El try-with-resources no tiene conocimiento del FileInputStream interno, por lo que si el constructor ObjectInputStream arroja una excepción, el FileInputStream nunca se cierra (hasta que el recolector de elementos no utilizados lo haga). La solucion es...

try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) { // do something with ois }

Esto no es tan elegante, pero es más robusto. Si esto es realmente un problema dependerá de qué excepciones se pueden arrojar durante la construcción de los objetos externos. ObjectInputStream puede lanzar IOException que bien puede ser manejado por una aplicación sin terminar. Muchas clases de flujo solo lanzan excepciones no verificadas, lo que puede dar como resultado la finalización de la aplicación.


Es una buena práctica usar Apache Commons para manejar objetos relacionados con IO.

En la cláusula IOUtils use IOUtils

IOUtils.closeQuietly (bWriter); IOUtils.closeQuietly (oWritter);

Fragmento de código a continuación.

BufferedWriter bWriter = null; OutputStreamWriter oWritter = null; try { oWritter = new OutputStreamWriter( httpConnection.getOutputStream(), "utf-8" ); bWriter = new BufferedWriter( oWritter ); bWriter.write( xml ); } finally { IOUtils.closeQuietly(bWriter); IOUtils.closeQuietly(oWritter); }


Esta es una pregunta sorprendentemente incómoda. (Incluso suponiendo que el código de la acquire; try { use; } finally { release; } es correcto).

Si la construcción del decorador falla, entonces no cerrará la transmisión subyacente. Por lo tanto, es necesario cerrar explícitamente el flujo subyacente, ya sea en el uso final o más difícil después de entregar el recurso al decorador con éxito.

Si una excepción hace que la ejecución falle, ¿realmente quieres tirar?

Algunos decoradores en realidad tienen recursos en sí mismos. La implementación de Sun actual de ZipInputStream por ejemplo, tiene una memoria de pila no Java asignada.

Se ha afirmado que (IIRC) dos tercios de los recursos utilizados en la biblioteca Java se implementan de una manera claramente incorrecta.

Mientras BufferedOutputStream cierra incluso en una IOException from flush , BufferedWriter cierra correctamente.

Mi consejo: cierre los recursos lo más directamente posible y no permita que contaminen otro código. OTOH, puede pasar demasiado tiempo con este tema: si se lanza OutOfMemoryError es agradable comportarse bien, pero otros aspectos de su programa son probablemente una prioridad más alta y el código de la biblioteca probablemente se rompa en esta situación de todos modos. Pero siempre escribo:

final FileOutputStream rawOut = new FileOutputStream(file); try { OutputStream out = new BufferedOutputStream(rawOut); ... write stuff out ... out.flush(); } finally { rawOut.close(); }

(Mira: ¡sin trampa!)

Y quizás use el modismo Execute Around.


Los JavaDocs de Sun incluyen RuntimeException en su documentación, como lo muestra el método de lectura (byte [], int, int) de InputStream; documentado como arrojando NullPointerException y IndexOutOfBoundsException.

El flush() FilterOutputStream solo está documentado como throwing IOException, por lo tanto, no arroja ningún RuntimeException . Cualquiera que pueda arrojarse probablemente esté envuelto en una IIOException .

Todavía podría arrojar un Error , pero no hay mucho que pueda hacer sobre eso; Sun recomienda que no intentes atraparlos.


Usualmente hago lo siguiente. En primer lugar, defina una clase basada en el método de plantilla para lidiar con el lío try / catch

import java.io.Closeable; import java.io.IOException; import java.util.LinkedList; import java.util.List; public abstract class AutoFileCloser { // the core action code that the implementer wants to run protected abstract void doWork() throws Throwable; // track a list of closeable thingies to close when finished private List<Closeable> closeables_ = new LinkedList<Closeable>(); // give the implementer a way to track things to close // assumes this is called in order for nested closeables, // inner-most to outer-most protected final <T extends Closeable> T autoClose(T closeable) { closeables_.add(0, closeable); return closeable; } public AutoFileCloser() { // a variable to track a "meaningful" exception, in case // a close() throws an exception Throwable pending = null; try { doWork(); // do the real work } catch (Throwable throwable) { pending = throwable; } finally { // close the watched streams for (Closeable closeable : closeables_) { if (closeable != null) { try { closeable.close(); } catch (Throwable throwable) { if (pending == null) { pending = throwable; } } } } // if we had a pending exception, rethrow it // this is necessary b/c the close can throw an // exception, which would remove the pending // status of any exception thrown in the try block if (pending != null) { if (pending instanceof RuntimeException) { throw (RuntimeException) pending; } else { throw new RuntimeException(pending); } } } } }

Observe la excepción "pendiente": se ocupa del caso en el que una excepción lanzada durante el cierre enmascararía una excepción que realmente nos interesaría.

Finalmente trata de cerrarse desde el exterior de cualquier secuencia decorada primero, por lo que si tiene un BufferedWriter envolviendo un FileWriter, trataremos de cerrar el BuffereredWriter primero, y si eso falla, aún trate de cerrar el FileWriter. (Tenga en cuenta que la definición de Closeable llama a close () para ignorar la llamada si la transmisión ya está cerrada)

Puede usar la clase anterior de la siguiente manera:

try { // ... new AutoFileCloser() { @Override protected void doWork() throws Throwable { // declare variables for the readers and "watch" them FileReader fileReader = autoClose(fileReader = new FileReader("somefile")); BufferedReader bufferedReader = autoClose(bufferedReader = new BufferedReader(fileReader)); // ... do something with bufferedReader // if you need more than one reader or writer FileWriter fileWriter = autoClose(fileWriter = new FileWriter("someOtherFile")); BufferedWriter bufferedWriter = autoClose(bufferedWriter = new BufferedWriter(fileWriter)); // ... do something with bufferedWriter } }; // .. other logic, maybe more AutoFileClosers } catch (RuntimeException e) { // report or log the exception }

Con este enfoque, nunca tendrá que preocuparse por el try / catch / finally para tratar nuevamente con los archivos de cierre.

Si esto es demasiado pesado para su uso, al menos piense en seguir el enfoque de prueba / captura y variable "pendiente" que utiliza.


Yo uso para cerrar transmisiones como esta, sin anidar try-catch en bloques finalmente

public class StreamTest { public static void main(String[] args) { FileOutputStream fos = null; BufferedOutputStream bos = null; ObjectOutputStream oos = null; try { fos = new FileOutputStream(new File("...")); bos = new BufferedOutputStream(fos); oos = new ObjectOutputStream(bos); } catch (Exception e) { } finally { Stream.close(oos,bos,fos); } } } class Stream { public static void close(AutoCloseable... array) { for (AutoCloseable c : array) { try {c.close();} catch (IOException e) {} catch (Exception e) {} } } }