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

Java ZipInputStream.GetNextry在某些zip文件上返回null,java,unzip,zipfile,compression,Java,Unzip,Zipfile,Compression,我有一个简单的代码来提取zip文件,它就像预期的一样正常工作,但在我的测试中,我用一些zip文件(从internet下载的字体、图标和模板)尝试了我的代码,以确保它能够提取提供的任何zip文件,但它不能处理一些zip文件,以下是重新生成此问题的最小化代码: package com.test.mytest; import java.io.FileInputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; im

我有一个简单的代码来提取zip文件,它就像预期的一样正常工作,但在我的测试中,我用一些zip文件(从internet下载的字体、图标和模板)尝试了我的代码,以确保它能够提取提供的任何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);
        }
    }
}
实际上,在我的实际应用程序中,我必须通过inputstreams提取zip文件。在上面的代码中,我试图提取“janne.zip”,我从下载了这个文件,我可以使用任何zip工具提取它,也可以通过“unzipFile(String zipName)”方法提取,但使用unzipStream(String zipName)方法

返回空值


如果您可以选择将
java.util.zip.ZipInputStream
替换为
org.apache.commons.compress.archivers.zip.ZipArchiveInputStream
(应该是API兼容的),那么请提供任何帮助然后,我刚刚在您的示例文件中测试了它,它似乎成功地工作了

一般来说,我发现commons compress在解包由工具(而不是
java.util.zip
类本身)创建的文件时比
java.util.zip
可靠得多

Edit:我在Eclipse中做了一些调试,看起来这个特定的zip文件在第一个条目的本地头的LOC签名(
0x04034b50
)之前有一个
0x30304b50
)。这是commons压缩的东西,但是
java.util.zip
没有-如果
j.u.z.ZipInputStream
看到的不是LOC签名,那么
getNextEntry()
将返回
null

有趣

我调试了你的代码,得到了同样的错误。我在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
),您将获得一个有效的头,您可以读取文件


我也有同样的问题!幸运的是,我能够解决它。
首先,我重置数据库中的blob数据,然后使用java代码使用ZipInputStream对其进行压缩。尽管我不确定,空ZipEntry问题可能是因为两件事:
1.数据库中的blob数据存储不正确(或者可能已经压缩,有些数据库在存储时压缩blob数据。您也可以通过谷歌搜索此数据)。
2.输入/输出流也可能导致故障,请参阅


下面是我所做工作的详细描述:
1.使用空\u 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.然后,我使用prepared语句在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();

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

Huh。真奇怪+1用于SSCCE并链接到示例文件。关闭
unzipFile
方法->@da_re中的
ZipFile
,这只是一个重新生成空问题的演示代码,关闭不会对我在这里试图指出的问题产生影响谢谢Roberts,这很奇怪。我想我会同意你的建议,肯定会尝试commons CompressAPI,因为我正在寻找一些可靠的解压缩API。再次感谢!太好了,你回来回答了原来的问题,+1帮我省了几个小时的搜索时间。真的很有趣!问题是我必须将这个实现交付给一个根本不懂文件头之类的东西的人。他说,如果我能够使用标准工具提取zip文件,那么为什么不通过您的代码呢。无论如何,谢谢-我可以通过ApacheCommonsCompress提取它,即使有这样的头
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();