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

时间:2013-03-20 11:14:58

标签: java unzip zipfile compression

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

返回null

任何帮助将不胜感激

3 个答案:

答案 0 :(得分:16)

无法解答为何此特定文件无法与java.util.zip一起使用,但如果您可以选择将java.util.zip.ZipInputStream替换为Apache commons-compress {{1} (这应该是API兼容的)然后我刚刚在你的示例文件上测试了它,它似乎成功运行。

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

编辑:我在Eclipse中做了一些调试,看起来这个特定的zip文件在LOC签名之前有single segment spanning marker java.util.zip {{1} 1}})第一个条目的本地标题。这是commons-compress knows how to handle0x30304b50没有 - 如果0x04034b50看到除LOC签名以外的任何内容,则java.util.zip将返回j.u.z.ZipInputStream。< / p>

答案 1 :(得分: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

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

答案 2 :(得分:0)


我遇到了同样的问题!幸运的是我能够解决它 首先我重置数据库中的blob数据然后使用java代码使用ZipInputStream压缩它。虽然我不确定,null ZipEntry问题可能是因为两件事:
1.数据库中的blob数据未正确存储(或者可能是已经压缩的数据库,某些数据库在存储时会压缩blob数据。你也可以google这个。)
2.输入/输出流也会带来麻烦,请参阅this

以下是我所做的详细说明:
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();
}

请注意,上述代码可以使用,但绝对不能证明编码标准和惯例 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();
}

上面的方法采用一个字节数组,将其压缩,然后将其放入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();

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