2012-03-06 22 views
15

Para el código similar al siguiente:DocumentBuilder.parse cerrar el InputStream

InputStream is = new FileInputstream("test.xml"); 
Document doc = DocumentBuilder.parser(is); 

Mi pregunta es si tengo que cerrar manualmente la corriente (invocar is.close()). ¿DocumentBuilder cierra el InputStream por mí?

Respuesta

7

Utilice el siguiente código de prueba para ver si la corriente de entrada está cerrada o no, y podría ver qué línea de código cierra la secuencia.

public class DocumentBuilderTest { 

public static void main(String[] args) { 
    try { 
    InputStream is = new MyInputStream("project.xml"); 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    DocumentBuilder documentBuilder = dbf.newDocumentBuilder(); 
    documentBuilder.parse(is); 
    } catch (Exception e) { 
    e.printStackTrace(); 
    } 
} 

static class MyInputStream extends FileInputStream { 
    public MyInputStream(String filename) throws FileNotFoundException { 
    super(filename); 
    } 

    @Override 
    public void close() throws IOException { 
    // here we log when the stream is close. 
    System.out.println("file input stream closed."); 
    Exception e = new Exception(); 
    e.printStackTrace(); 
    super.close(); 
    } 

} 
} 

Si el flujo de entrada pasa a la DocumentBuilder está cerrado o no depende de la aplicación DOMParser. En mi entorno, el flujo de entrada de archivos está cerrado, ver el seguimiento de la pila a continuación:

at DocumentBuilderTest$MyInputStream.close(DocumentBuilderTest.java:37) 
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.close(XMLEntityManager.java:3047) 
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.close(UTF8Reader.java:661) 
at com.sun.xml.internal.stream.Entity$ScannedEntity.close(Entity.java:441) 
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.endEntity(XMLEntityManager.java:1406) 
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1763) 
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipSpaces(XMLEntityScanner.java:1543) 
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$TrailingMiscDriver.next(XMLDocumentScannerImpl.java:1400) 
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648) 
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511) 
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808) 
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737) 
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119) 
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:235) 
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284) 
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:124) 
at DocumentBuilderTest.main(DocumentBuilderTest.java:22) 

lo que no podía cerrar manualmente la corriente en este ejemplo específico. Sin embargo, siempre es una buena idea cerrar la secuencia de entrada cuando esté seguro de que la transmisión ya no se utilizará. En su caso, una vez que se analiza el documento, la transmisión de entrada ya no es necesaria, por lo que la transmisión se puede cerrar de forma segura, y le sugiero que lo haga.

2

La documentación no menciona que cierre la transmisión, y no esperaría que cerrara la transmisión por usted.

Para estar seguro, podría leer el código fuente, o verificar si está abierto en un caso de ejemplo simple después de llamar a parse().

Pero la respuesta corta: Sí, debe cerrarla manualmente después.

+0

¡Gracias! Haré un simple ejemplo. –

+0

No hay problema. Además, supongo que sin decirlo explícitamente, el método no lo cerraría. Espero que los métodos que actúan sobre los objetos los paso para actuar sobre los objetos lo menos posible. Llamar a .close() se consideraría una falta de responsabilidad para mí (el método de análisis no tiene llamadas comerciales .close()). – Corbin

+1

Para mi sorpresa, DocumentBuilder.parse cierra la secuencia en mi ejemplo. –

3

El contrato habitual es que el código que adquiere un recurso debe liberarlo. Esta es una buena práctica, ya que significa que si se lanza una excepción por cualquier código intermedio, no se pierde el recurso.

utilizar un bloque try-with-resources:

try (InputStream in = new FileInputStream("foo")) { 
    // process data 
} 

Para pre-Java 7:

InputStream in = new FileInputStream("foo"); 
try { 
    // process data 
} finally { 
    in.close(); 
} 
3

Lo que hice fue extender FilterInputStream, y anular close() m implementación de ethod para evitar el cierre de InputStream

public class HackInputStream 
    extends FilterInputStream { 

    public HackInputStream(InputStream in) { 
     super(in); 
    } 

    @Override 
    public void close() { 
     // this does not close stream. 
     // use hackedClose() instead. 
    } 

    public void hackedClose() 
      throws IOException { 
     super.close(); 
    } 


} 
Cuestiones relacionadas