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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15521966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:55:39  来源:igfitidea点击:

ZipInputStream.getNextEntry returns null on some zip files

javaunzipzipfilecompression

提问by spring_dev101

I have a simple code to extract zip files, it was working just fine as expected but during my test I tried my code with some zip files (fonts, icons and templates I downloaded from internet) just to make sure it should extract any zip files provided, but its not working with some zip files, here is the minimized code to regenerate this issue:

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

actually In my real application i have to extract zip files through inputstreams. In the code above I am trying to extract "janne.zip" I downloaded this file from http://www.iconian.com/fonts/janne.zipI am able to extract it using any zip-tool and surprisingly through "unzipFile(String zipName)" method as well, but with unzipStream(String zipName) method

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

ZipEntry ze = zis.getNextEntry();

returns null

返回空值

any help would be appreciated

任何帮助,将不胜感激

回答by Ian Roberts

Not an answer as to why this particular file doesn't work with java.util.zip, but if you have the option to replace your use of java.util.zip.ZipInputStreamwith the Apache commons-compressorg.apache.commons.compress.archivers.zip.ZipArchiveInputStream(which should be API-compatible) then I've just tested that on your example file and it seems to work successfully.

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

Generally I find commons-compress to be much more reliable than java.util.zipat unpacking files created by tools other than the java.util.zipclasses themselves.

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

Edit:I've done a bit of debugging in Eclipse and it looks like this particular zip file has a single segment spanning markerof 0x30304b50before the LOC signature (0x04034b50) of the first entry's local header. This is something that commons-compress knows how to handlebut java.util.zipdoesn't - if j.u.z.ZipInputStreamsees anything other than a LOC signature then getNextEntry()will return null.

编辑:我已经做了一些在Eclipse调试的,它看起来像这个特殊的zip文件中有一个单一的区段跨过标记0x30304b50组委会签名(前0x04034b50第一入口的地方标头的)。这是 commons-compress知道如何处理java.util.zip知道的j.u.z.ZipInputStream事情- 如果看到除 LOC 签名之外的任何内容,getNextEntry()则将返回null.

回答by Mirko

Funny!

有趣的!

I debugged your code and got the same error. I found an header check in the ZipInputStream implementation, but not in the ZipFile implementation.

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

Dont ask me why, but the header in your zip file is not valid!

不要问我为什么,但您的 zip 文件中的标题无效

Your file is starting with: 50 4B 30 30 50 4B 03 04
A valid Zip File Header is: 50 4B 03 04

If you delete the first bytes (50 4B 30 30) from your file you got a valid header an you can read you file!

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

回答by tewari2312


I was having the same problem ! Lucky for me I was able to resolve it.
first i reset the blob data in the database then used java code to zip it using ZipInputStream. Although I am not sure, the null ZipEntry problem could be because of 2 things:
1. The blob data in the database is not stored correctly (or may be its already compressed, some databases compress blob data at the time of storage. you can google this too).
2. The input/output streams can also cause trouble, see this


我遇到了同样的问题!幸运的是我能够解决它。
首先我重置数据库中的 blob 数据,然后使用 java 代码使用 ZipInputStream 压缩它。虽然我不确定,空 ZipEntry 问题可能是因为 2 件事:
1. 数据库中的 blob 数据没有正确存储(或者可能已经压缩,某些数据库在存储时压缩 blob 数据。您可以谷歌这个太)。
2.输入/输出流也会引起麻烦,看这个



Here is detailed description of what I did:
1. reset the blob field in database using EMPTY_BLOB and commit changes
2. used the below java program to update the blob field with a .xls file

这是我所做的详细说明:
1. 使用 EMPTY_BLOB 重置数据库中的 blob 字段并提交更改
2. 使用下面的 java 程序用 .xls 文件更新 blob 字段

DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver ()); // register driver

Connection conn =
   DriverManager.getConnection ("jdbc:oracle:thin:@my-local-database:1521:test", "test1", "test1");

// It's faster when auto commit is off: 
conn.setAutoCommit (false);

try
{
      PreparedStatement pstmt = conn.prepareStatement("update content set file_content = ? where CONTENT_ID=2006");
      File blob = new File("C:/Users/ankur/Desktop/Book1.xls");
      FileInputStream in = new FileInputStream(blob);

      pstmt.setBinaryStream(1, in); 
      pstmt.executeUpdate();
      conn.commit();
      conn.close();
      System.out.println("file updated");
}
catch (SQLException e)
{
   e.printStackTrace();
}

Please note that the above code will work but it absolutely does not demonstrate coding standards and practices.
3. Used the below zip method to compress data

请注意,上面的代码可以工作,但它绝对没有展示编码标准和实践。
3.使用下面的zip方法压缩数据

public byte[] zipByteArray(String primaryKey, byte[] input) throws IOException{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ZipOutputStream zos = new ZipOutputStream(baos);
    ZipEntry entry = new ZipEntry(primaryKey);
    entry.setSize(input.length);
    zos.putNextEntry(entry);
    zos.write(input);
    zos.closeEntry();
    zos.close();
    return baos.toByteArray();
}

The above method takes a byte array, zips it, puts it into a ByteArrayOutputStream. You can choose to use the ByteArrayOutputStream itself, due to some requirements I am converting it to byte array.
4. I then insert the above byte array in blob field using prepared statement
5. If I use the unzip code given below, it works fine!

上面的方法接受一个字节数组,压缩它,把它放到一个 ByteArrayOutputStream 中。您可以选择使用 ByteArrayOutputStream 本身,由于某些要求,我将其转换为字节数组。
4. 然后我使用准备好的语句在 blob 字段中插入上面的字节数组
5. 如果我使用下面给出的解压缩代码,它工作正常!

public byte[] unzipInputStream(InputStream is) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = null;
    ZipInputStream zipIs = new ZipInputStream(new BufferedInputStream(is));
    byteArrayOutputStream = new ByteArrayOutputStream();
    ZipEntry entry = zipIs.getNextEntry();
    while (entry != null) {
        byte[] tmp = new byte[2048];
        BufferedOutputStream bos = null;
        bos = new BufferedOutputStream(byteArrayOutputStream);
        int size = 0;
        while ((size = zipIs.read(tmp)) != -1) {
            bos.write(tmp, 0, size);
        }
        bos.flush();
        bos.close();
        entry = zipIs.getNextEntry();
    }
    zipIs.close();
    return byteArrayOutputStream.toByteArray();

The output of the above method is the unzipped data.

上述方法的输出是解压后的数据。