【发布时间】:2021-03-04 19:45:46
【问题描述】:
我想流式传输包含几个非常大(~1GByte)的 XML 文件的 ZIP 文件。我可以将每个 zip 文件中的数据读入缓冲区并从中创建一个 XMLStream - 但为了节省内存,我更愿意动态处理数据。
@Test
public void zipStreamTest() throws IOException, XMLStreamException {
FileInputStream fis = new FileInputStream("archive.zip");
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ei;
while ((ei = zis.getNextEntry()) != null){
XMLEventReader xr = XMLInputFactory.newInstance().createXMLEventReader(zis);
while (reader.hasNext()) {
XMLEvent xe = xr.nextEvent();
// do some xml event processing..
}
zis.closeEntry();
}
zis.close();
}
问题:我在执行zis.closeEntry(); 时得到java.io.IOException: Stream closed。当我删除该行时,zis.getNextEntry() 会引发相同的错误,如果它们仍然自动打开,则会关闭以前的条目。
我的 XML 流阅读器似乎在 XML 文件的末尾中断了流,因此无法处理 zip 的其余部分。
我是有实现错误还是我对流如何工作的概念不正确?
注意:要使这个最小的可复制示例,您只需要一个 zip 文件“archive.zip”,其中包含任何有效的 XML 文件(zip 中没有子目录!)。然后,您可以使用 JUnit 运行 sn-p。
【问题讨论】:
-
The implementation of XMLEventReader 不会出现在底层源代码附近,除非你显式调用它的
close()方法,所以我猜你在某个地方调用了 close()。考虑在您的问题中提供minimal reproducible example。 -
我建议使用
ZipFile而不是ZipInputStream,正如answer by Alexandra Dudkina 中所建议的那样,但是如果您正在处理数据流,例如下载,因此想继续使用ZipInputStream,您应该将它包装为CloseShieldInputStream来自Apache Commons IO (或其他类似的帮助类) 在getNextEntry()循环内。 -
@Andreas:非常感谢!您的解决方案效果很好。请制定您的解决方案作为答案,以便我可以接受。 Re:ZipFile:这是显而易见的解决方案,但我的 zip 源和目标不是文件,而是网络流和/或数据库套接字。