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

2022-09-04 07:13:31

我有一个简单的代码来提取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);
        }
    }
}

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

ZipEntry ze = zis.getNextEntry();

返回空值

任何帮助将不胜感激


答案 1

不是关于为什么这个特定文件不能使用的答案,但是如果你可以选择用Apache commons-compress(应该是API兼容的)替换你的使用,那么我刚刚在你的示例文件上测试了它,它似乎可以成功工作。java.util.zipjava.util.zip.ZipInputStreamorg.apache.commons.compress.archivers.zip.ZipArchiveInputStream

一般来说,我发现commons-compress比解压缩由类本身以外的工具创建的文件要可靠得多。java.util.zipjava.util.zip

编辑:我已经在Eclipse中进行了一些调试,看起来这个特定的zip文件在第一个条目的本地标头的LOC签名()之前有一个段跨越标记。这是commons-compress知道如何处理但不知道的事情 - 如果看到LOC签名以外的任何东西,那么将返回。0x30304b500x04034b50java.util.zipj.u.z.ZipInputStreamgetNextEntry()null


答案 2

有趣!

我调试了您的代码并得到了相同的错误。我在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

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


推荐