【发布时间】:2019-12-12 22:51:58
【问题描述】:
我一直在尝试创建一个 Java 程序,该程序将从在线 API 读取 zip 文件,将它们解压缩到内存中(而不是文件系统中),然后将它们加载到数据库中。 由于解压后的文件需要按特定顺序加载到数据库中,因此我必须先解压所有文件,然后才能加载其中的任何一个。
我基本上使用 StackOverflow 上的 another question 作为如何做到这一点的模型。使用来自util.zip 的ZipInputStream 我可以使用较小的 ZIP(压缩后 0.7MB ~ 解压缩 4MB)来执行此操作,但是当我遇到更大的文件(压缩后 25MB,解压缩时 135MB)时,两个最大的文件没有被读入记忆。我什至无法为这些较大的文件(8MB 和 120MB,后者构成 zip 文件中的绝大多数数据)检索 ZipEntry。没有抛出异常,我的程序继续运行,直到它尝试访问无法写入的解压缩文件并抛出 NullPointerException。
我正在使用 Jsoup 从网上获取 zipfile。
有没有人有这方面的经验并且可以就我为什么无法检索 zip 文件的完整内容提供指导?
以下是我正在使用的代码。我在 HashMap 中以InputStreams 的形式收集解压缩文件,当没有更多的ZipEntrys 时,程序应该停止寻找ZipEntrys 的剩余空间。
private Map<String, InputStream> unzip(ZipInputStream verZip) throws IOException {
Map<String, InputStream> result = new HashMap<>();
while (true) {
ZipEntry entry;
byte[] b = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream();
int l;
entry = verZip.getNextEntry();//Might throw IOException
if (entry == null) {
break;
}
try {
while ((l = verZip.read(b)) > 0) {
out.write(b, 0, l);
}
out.flush();
}catch(EOFException e){
e.printStackTrace();
}
catch (IOException i) {
System.out.println("there was an ioexception");
i.printStackTrace();
fail();
}
result.put(entry.getName(), new ByteArrayInputStream(out.toByteArray()));
}
return result;
}
如果我的程序利用文件系统解压缩文件,我会不会更好?
【问题讨论】:
-
您不应该尝试将所有这些数据保存在内存中。当需要写入数据库时,只需通过
ZipEntrys,而不是尝试将它们全部放在 Map 中。此外,您需要while ((l = verZip.read(b)) >= 0)——注意>=而不是>。否则,您的代码将在第一次遇到零字节时停止读取数据。 -
@VGR 我编辑了帖子以回答这个问题。解压后的文件需要按特定顺序加载到数据库中,所以我必须先解压所有文件,然后再加载。
-
@VGR 您对读取循环的评论不正确。他正在读入一个缓冲区,返回值是一个计数,而不是一个字节值。这段代码永远不会返回零,除非
b[]的长度为零。 -
当你忽略它们时,你怎么知道没有抛出异常?
-
所需的插入顺序与 zip 文件中的条目顺序是否不同?在我看来,通过将名称存储在设计上无序的 HashMap 中,您会失去任何排序。
标签: java memory zip jsoup zipinputstream