ZipInputStream.getNextEntry在某些zip文件上返回null

spr*_*101 10 java compression unzip zipfile

我有一个简单的代码来提取zip文件,它正常工作正常,但在我的测试期间我尝试了我的代码与一些zip文件(我从互联网上下载的字体,图标和模板)只是为了确保它应该提取任何zip文件提供,但它不使用一些zip文件,这里是重新生成此问题的最小化代码:

package com.test.mytest;

import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class ZipExtractTest {

    public static final String ZIP_FILE = "/Users/XXXXX/Downloads/janne.zip";

    public static void main(String[]args) {
        unzipFile(ZIP_FILE);
        unzipStream(ZIP_FILE);
    }

    public static void unzipFile(String zipName) {
        try {

            ZipFile zf = new ZipFile(zipName);

            Enumeration ent = zf.entries();

            while(ent.hasMoreElements()) {
                System.out.println(ent.nextElement());
            }

        } catch(Exception e) {
            System.out.println(e);
        }
    }

    public static void unzipStream(String zipName) {
        try {
            ZipInputStream zis = new ZipInputStream(new FileInputStream(zipName));
            ZipEntry ze = zis.getNextEntry();

            if(ze == null) {
                System.out.println("unable to get first entry from zip file");
                zis.close();
                return;
            }

            while(ze != null) {
                System.out.println("Entry Found: " + ze);
                ze = zis.getNextEntry();
            }

            zis.closeEntry();
            zis.close();

        } catch(Exception e) {
            System.out.println(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上在我的实际应用程序中,我必须通过输入流提取zip文件.在上面的代码中我试图提取"janne.zip"我从http://www.iconian.com/fonts/janne.zip下载了这个文件我能够使用任何zip工具提取它并且令人惊讶地通过"unzipFile" (String zipName)"方法也是如此,但是使用unzipStream(String zipName)方法

ZipEntry ze = zis.getNextEntry();
Run Code Online (Sandbox Code Playgroud)

返回null

任何帮助,将不胜感激

Ian*_*rts 16

关于为什么这个特定文件无法使用的答案java.util.zip,但是如果你可以选择java.util.zip.ZipInputStreamApache commons-compress 替换你的使用org.apache.commons.compress.archivers.zip.ZipArchiveInputStream(这应该是API兼容的),那么我刚刚测试了你的例子文件似乎成功.

通常我发现commons-compress比java.util.zip解包由java.util.zip类本身以外的工具创建的文件更可靠.

编辑:我在Eclipse中做了一些调试,看起来这个特定的zip文件在第一个条目的本地标题的LOC signature()之前有一个跨越标记.这是commons-compress 知道如何处理但不知道的事情- 如果看到除了LOC签名以外的任何内容,则会返回.0x30304b500x04034b50java.util.zipj.u.z.ZipInputStreamgetNextEntry()null


Mir*_*rko 5

滑稽!

我调试了你的代码并得到了同样的错误.我在ZipInputStream实现中找到了一个头检查,但在ZipFile实现中没有.

不要问我原因,但是你的zip文件中的标题无效!

Your file is starting with: 50 4B 30 30 50 4B 03 04
A valid Zip File Header is: 50 4B 03 04
Run Code Online (Sandbox Code Playgroud)

如果50 4B 30 30从文件中删除第一个字节(),则会得到一个有效的标题,您可以读取文件!