2012-03-06 26 views
15

Đối với mã tương tự như sau:Liệu DocumentBuilder.parse đóng InputStream

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

Câu hỏi của tôi là liệu tôi cần phải đóng dòng bằng tay (gọi is.close()). DocumentBuilder có đóng InputStream cho tôi không?

Trả lời

7

Sử dụng mã kiểm tra sau để xem luồng đầu vào có được đóng hay không và bạn có thể xem dòng mã nào đóng luồng.

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(); 
    } 

} 
} 

Cho dù luồng đầu vào được chuyển đến DocumentBuilder có được đóng hay không phụ thuộc vào việc triển khai DOMParser. Trong môi trường của tôi, luồng đầu vào của tệp bị đóng, hãy xem dấu vết ngăn xếp bên dưới:

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) 

Vì vậy, bạn không thể đóng luồng theo cách thủ công trong ví dụ cụ thể này. Tuy nhiên, bạn nên luôn đóng luồng đầu vào khi bạn chắc chắn rằng luồng sẽ không được sử dụng nữa. Trong trường hợp của bạn, khi tài liệu được phân tích cú pháp, luồng đầu vào không còn cần thiết, vì vậy luồng có thể được đóng một cách an toàn và tôi khuyên bạn nên làm điều đó.

2

Tài liệu không đề cập đến việc đóng luồng và tôi không mong đợi nó đóng luồng cho bạn.

Để chắc chắn, bạn có thể đọc mã nguồn hoặc kiểm tra xem nó có mở trong một trường hợp ví dụ đơn giản sau khi gọi phân tích cú pháp() hay không.

Nhưng câu trả lời ngắn gọn: Có, bạn cần phải đóng thủ công sau đó.

+0

Cảm ơn bạn! Tôi sẽ làm một ví dụ đơn giản. –

+0

Không sao cả. Ngoài ra, tôi sẽ giả định rằng không nói rõ ràng như vậy, phương pháp sẽ không đóng nó. Tôi mong đợi các phương pháp hành động trên các đối tượng tôi truyền chúng để hành động trên các đối tượng càng ít càng tốt. Gọi .close() sẽ được xem là vi phạm trách nhiệm đối với tôi (phương thức phân tích cú pháp không có lệnh gọi kinh doanh .đóng()). – Corbin

+1

Tôi rất ngạc nhiên khi DocumentBuilder.parse đóng luồng trong ví dụ của tôi. –

3

Hợp đồng thông thường là mã mua lại tài nguyên phải phát hành nó. Đây là thực hành tốt vì nó có nghĩa là nếu một ngoại lệ được ném bởi bất kỳ mã can thiệp nào, bạn không bị rò rỉ tài nguyên.

Sử dụng một khối try-with-resources:

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

Đối với pre-Java 7:

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

Nếu nhu cầu của bạn là để có luồng của mình không đóng cửa sau khi DOM phân tích cú pháp (theo thứ tự để có thể tiếp tục để đọc nó, ví dụ), xem chủ đề này: Java create InputStream from ZipInputStream entry

3

Điều tôi đã làm là mở rộng FilterInputStream và ghi đè close() m triển khai ethod để ngăn đóng 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(); 
    } 


} 
Các vấn đề liên quan