【发布时间】:2018-04-22 20:46:01
【问题描述】:
我正在尝试从嵌套的 zip 存档中提取文件并在内存中处理它们。
这个问题不是关于什么:
如何在 Java 中读取 zip 文件:不,问题是如何在 zip 中读取 zip 文件中的 zip 文件,依此类推(如嵌套 zip 文件中)。
在磁盘上写入临时结果:不,我要在内存中完成所有操作。我使用将结果临时写入磁盘的效率不高的技术找到了许多答案,但这不是我想要做的。
例子:
Zipfile -> Zipfile1 -> Zipfile2 -> Zipfile3
目标:提取每个嵌套 zip 文件中的数据,全部在内存中并使用 Java。
ZipFile 是答案,你说?不,不是,它适用于第一次迭代,即:
Zipfile -> Zipfile1
但是一旦你到达 Zipfile2,并执行:
ZipInputStream z = new ZipInputStream(zipFile.getInputStream( zipEntry) ) ;
你会得到一个 NullPointerException。
我的代码:
public class ZipHandler {
String findings = new String();
ZipFile zipFile = null;
public void init(String fileName) throws AppException{
try {
//read file into stream
zipFile = new ZipFile(fileName);
Enumeration<?> enu = zipFile.entries();
exctractInfoFromZip(enu);
zipFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//The idea was recursively extract entries using ZipFile
public void exctractInfoFromZip(Enumeration<?> enu) throws IOException, AppException{
try {
while (enu.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) enu.nextElement();
String name = zipEntry.getName();
long size = zipEntry.getSize();
long compressedSize = zipEntry.getCompressedSize();
System.out.printf("name: %-20s | size: %6d | compressed size: %6d\n",
name, size, compressedSize);
// directory ?
if (zipEntry.isDirectory()) {
System.out.println("dir found:" + name);
findings+=", " + name;
continue;
}
if (name.toUpperCase().endsWith(".ZIP") || name.toUpperCase().endsWith(".GZ")) {
String fileType = name.substring(
name.lastIndexOf(".")+1, name.length());
System.out.println("File type:" + fileType);
System.out.println("zipEntry: " + zipEntry);
if (fileType.equalsIgnoreCase("ZIP")) {
//ZipFile here returns a NULL pointer when you try to get the first nested zip
ZipInputStream z = new ZipInputStream(zipFile.getInputStream(zipEntry) ) ;
System.out.println("Opening ZIP as stream: " + name);
findings+=", " + name;
exctractInfoFromZip(zipInputStreamToEnum(z));
} else if (fileType.equalsIgnoreCase("GZ")) {
//ZipFile here returns a NULL pointer when you try to get the first nested zip
GZIPInputStream z = new GZIPInputStream(zipFile.getInputStream(zipEntry) ) ;
System.out.println("Opening ZIP as stream: " + name);
findings+=", " + name;
exctractInfoFromZip(gZipInputStreamToEnum(z));
} else
throw new AppException("extension not recognized!");
} else {
System.out.println(name);
findings+=", " + name;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Findings " + findings);
}
public Enumeration<?> zipInputStreamToEnum(ZipInputStream zStream) throws IOException{
List<ZipEntry> list = new ArrayList<ZipEntry>();
while (zStream.available() != 0) {
list.add(zStream.getNextEntry());
}
return Collections.enumeration(list);
}
【问题讨论】:
-
"(将很快编辑)" - 不要发布部分问题。等到您提出完整的问题后再发布。
-
您的主要问题是您首先必须在 ZipInputStream 上使用
getNextEntry()寻找正确的 zip 条目。 -
抱歉发布错误。下班后会更正帖子。我真的被这个困住了
-
以后请考虑把你的代码变成minimal reproducible example;也就是说,最好是一个带有 main() 方法的 .java 文件,我们可以编译并运行它来重现问题。
-
无论如何,你真正的问题似乎是你的
zipFile变量总是引用最外面的文件。尝试将 ZipEntry 从内部 ZipInputStreams 之一传递到zipFile.getInputStream()会失败,这并不奇怪。 (唯一的惊喜是它不会抛出 IllegalArgumentException。)由于似乎没有任何方法可以从 InputStream 实例化 ZipFile,因此您最好的选择似乎是放弃 ZipFile 并直接使用 ZipInputStreams,例如JMax 建议如下。
标签: java zip zipfile zipinputstream