13

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

返回空

任何帮助,将不胜感激

4

3 回答 3

21

不是关于为什么这个特定文件不能与java.util.zip.文件,它似乎工作成功。java.util.zip.ZipInputStream org.apache.commons.compress.archivers.zip.ZipArchiveInputStream

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

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

于 2013-03-20T11:48:40.737 回答
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),您将获得一个有效的标题,您可以读取您的文件!

于 2013-03-20T13:06:34.137 回答
2


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


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

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

于 2016-05-13T06:58:58.670 回答