¿Necesito cerrar () FileReader y BufferedReader?

188

Estoy leyendo un archivo local usando un BufferedReader envuelto alrededor de un FileReader:

BufferedReader reader = new BufferedReader(new FileReader(fileName));
// read the file
// (error handling snipped)
reader.close();

¿Necesito close()el FileReadertambién, o el envoltorio manejará eso? He visto código donde la gente hace algo como esto:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);
// read the file
// (error handling snipped)
bReader.close();
fReader.close();

Este método se llama desde un servlet, y me gustaría asegurarme de no dejar ningún controlador abierto.

Zilk
fuente
44
Ya sabes, puedes leer la fuente de información como esta. Todo está allí en src.zip en el directorio de instalación de JDK, o puede leerlo en línea en, por ejemplo, docjar.com/html/api/java/io/BufferedReader.java.html
gustafc
50
Decirle a alguien que lea la fuente es peor que decir "RTFM!". ¿Y si la fuente tiene un error? implícitamente queremos saber cuál es el comportamiento correcto ?
Raedwald
1
Bueno ... desde este punto de vista: señalar las especificaciones de API no es mejor entonces. Si la fuente no tiene un error que hace que no se comporte como se especifica en los documentos, no puede confiar en los documentos. Entonces no hay una buena manera de responder a esa pregunta.
Atmocreations
@Atmocreations La próxima versión de mantenimiento puede corregir alegremente un error en el que confía si solo mira la fuente. Realmente necesita saber cuál es el comportamiento documentado. No hay nada malo en mirar la fuente, por supuesto, pero no puedes asumir que la fuente no cambiará. Cambiar el comportamiento documentado suele ser mucho más importante que arreglar un error.
James Moore

Respuestas:

202

No.

BufferedReader.close()

cierra la secuencia de acuerdo con javadoc para BufferedReader y InputStreamReader

tanto como

FileReader.close()

hace.

Atmocreations
fuente
12
A menos que el constructor BufferedReaderarroje una excepción. Es más limpio solo para cerrar la secuencia subyacente, aunque debe tener cuidado con los decoradores con otros recursos y almacenamiento en búfer.
Tom Hawtin - tackline
9
El Javadoc no dice si BufferedReader.close()cierra el lector subyacente. Su descripción simplemente se copia de Reader.close(). Este puede ser el comportamiento real en la práctica, pero no está documentado.
John Kugelman
3
Si el comportamiento real fue diferente, entonces debería haberse documentado como tal. De lo contrario, la documentación es inútil. El programador debe poder considerar la documentación como completa y específica.
Atmocreations
66
No importa si la documentación real debería haberse cambiado o no, Reader#close()los javadoc no dicen si cierra o no está envuelto Reader. Todo lo que dice relacionado con eso es Closes the stream and releases any system resources associated with it.que no es lo suficientemente explícito como para decir que cierra o no el recurso. 'Liberar el recurso' podría estar eliminando cualquier referencia al recurso en el BufferedReader ... lo que significaría que el recurso no está cerrado.
searchengine27
99

Como otros han señalado, solo necesita cerrar el envoltorio exterior.

BufferedReader reader = new BufferedReader(new FileReader(fileName));

Hay una posibilidad muy pequeña de que esto pueda filtrar un identificador de archivo si el BufferedReaderconstructor arrojó una excepción (por ejemplo OutOfMemoryError). Si su aplicación se encuentra en este estado, el cuidado que debe tener su limpieza dependerá de lo importante que sea que no priva al sistema operativo de los recursos que podría asignar a otros programas.

La interfaz Closeable se puede usar si un constructor de contenedor puede fallar en Java 5 o 6:

Reader reader = new FileReader(fileName);
Closeable resource = reader;
try {
  BufferedReader buffered = new BufferedReader(reader);
  resource = buffered;
  // TODO: input
} finally {
  resource.close();
}

El código Java 7 debe usar el patrón de prueba con recursos :

try (Reader reader = new FileReader(fileName);
    BufferedReader buffered = new BufferedReader(reader)) {
  // TODO: input
}
McDowell
fuente
1
"El código Java 7 debe usar el patrón de prueba con recursos". Gracias, eso es exactamente lo que estaba buscando. Esta solución fue escrita en '09, por lo que el paradigma de probar con recursos probablemente debería ser la nueva recomendación. Además, ofrece una mejor respuesta al OP sobre la respuesta aceptada y más votada.
Tresf
5

Según la fuente de BufferedReader, en este caso bReader.close llame a fReader.close, por lo que técnicamente no tiene que llamar a este último.

Csaba_H
fuente
Dado que hay documentación que explica cómo debe usarse, primero debe mirar la documentación: cualquier desviación en el código es un error.
hmijail llora a los despedidos el
5

El código fuente de BufferedReader muestra que el subyacente se cierra cuando cierra BufferedReader.

Brian Agnew
fuente
1
Realmente quiero darle un visto bueno a esto para vincularlo a algo concreto, pero esto solo se refiere a la implementación de OpenJDK, y dado que los JavaDoc no están claros Reader#close(), esto no proporciona evidencia concreta de que Oracle JDK, por ejemplo, esté implementado en un Moda similar.
searchengine27
4

Después de verificar el código fuente, encontré eso para el ejemplo:

FileReader fReader = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(fReader);

el método close () en el objeto BufferedReader llamaría al método abstracto close () de la clase Reader que finalmente llamaría al método implementado en la clase InputStreamReader , que luego cierra el objeto InputStream .

Entonces, solo bReader.close () es suficiente.

Anup Verma
fuente
44
Lo que muestra el código fuente no es citable como referencia. Es lo que dice la especificación , en este caso el Javadoc, en lo que se puede confiar.
Marqués de Lorne
1

A partir de Java 7, puede usar la declaración de prueba con recursos

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

Debido a que la BufferedReaderinstancia se declara en una declaración de prueba con recursos, se cerrará independientemente de si la declaración de prueba se completa de manera normal o abrupta. Por lo tanto, no necesita cerrarlo usted mismo en la finallydeclaración. (Este también es el caso con las declaraciones de recursos anidados)

Esta es la forma recomendada de trabajar con recursos. Consulte la documentación para obtener información más detallada.

Claudiu
fuente
Esto es casi idéntico a la respuesta de @ mcdowell de 2009, que también cubre algunos problemas extremos que podrían ocurrir.
Tresf
0

Solo necesita cerrar el bufferedReader, es decir, reader.close () y funcionará bien.

Jitendra
fuente
0

Llego tarde, pero:

BufferReader.java:

public BufferedReader(Reader in) {
  this(in, defaultCharBufferSize);
}

(...)

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        try {
            in.close();
        } finally {
            in = null;
            cb = null;
        }
    }
}
Dmitry Gashko
fuente
Eeeeh que no responde a su pregunta? Ella / Él pregunta si es necesario cerrar FileReader y BufferedReader, no un código de ejemplo.
TornaxO7
@ TornaxO7 no, no es un código de ejemplo. Acabo de escribir parte del código fuente de Java. Por lo tanto, si hace clic en alguna función de BufferedReader con la tecla ctrl / cmd (depende del IDE), puede ver el código fuente de BufferedReader y puede encontrar ese fragmento de código. Entonces, como puede ver BufferedReader solo cierre FileReader por sí mismo ('in' es FileReader en este caso, por lo tanto, cuando llama a bufferReader.close () llama a in.close () dentro, exactamente en el método bufferReader.close)
Dmitry Gashko
0

Usted ¿No es necesario cerrar el lector / grabador envueltos.

Si ha echado un vistazo a los documentos ( Reader.close(), Writer.close()), verá que en Reader.close()él dice:

Cierra la secuencia y libera todos los recursos del sistema asociados a ella.

Lo que simplemente dice que "libera todos los recursos del sistema asociados con él". A pesar de que no confirma ... te da un empujón para comenzar a mirar más profundo. y si vas Writer.close()solo dice que se cierra solo.

En tales casos, nos referimos a OpenJDK para echar un vistazo al código fuente.

En BufferedWriter Line 265 verás out.close(). Entonces no se está cerrando a sí mismo ... Es algo más. Si busca en la clase las ocurrencias de " out", notará que en el constructor de la línea 87, que outes el escritor, la clase termina donde llama a otro constructor y luego asigna el outparámetro a sí mismoout variable.

Entonces ... ¿Qué hay de los demás? Puede ver un código similar en BufferedReader Line 514 , BufferedInputStream Line 468 y InputStreamReader Line 199 . No conozco a otros, pero esto debería ser suficiente para suponer que sí.

Omar Abdul'Azeez
fuente