如何创建一个multipart zip文件并将其读回?

时间:2016-12-20 16:29:14

标签: java zip bytearrayoutputstream zipoutputstream bytearrayinputstream

如何正确压缩字节到Array ( [0] => Array ( [0] => 2 [1] => 1 ) [1] => Array ( [0] => 4 [1] => 1 ) ) ,然后使用ByteArrayOutputStream读取?我有以下方法:

ByteArrayInputStream

当我执行此代码时,底部的断言失败,因为private byte[] getZippedBytes(final String fileName, final byte[] input) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ZipOutputStream zipOut = new ZipOutputStream(bos); ZipEntry entry = new ZipEntry(fileName); entry.setSize(input.length); zipOut.putNextEntry(entry); zipOut.write(input, 0, input.length); zipOut.closeEntry(); zipOut.close(); //Turn right around and unzip what we just zipped ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(bos.toByteArray())); while((entry = zipIn.getNextEntry()) != null) { assert entry.getSize() >= 0; } return bos.toByteArray(); } entry.size。我不明白为什么提取的实体与压缩的实体不匹配。

2 个答案:

答案 0 :(得分:14)

为什么尺寸为-1?

getNextEntry中调用ZipInputStream只需将读取光标放在要读取的条目的开头。

大小(以及其他元数据)存储在实际数据的末尾,因此当光标位于开头时不可用。

只有在您阅读完整条目数据或只是转到下一个条目后,这些信息才可用。

例如,转到下一个条目:

// position at the start of the first entry
entry = zipIn.getNextEntry();
ZipEntry firstEntry = entry;    
// size is not yet available
System.out.println("before " + firstEntry.getSize()); // prints -1

// position at the start of the second entry
entry = zipIn.getNextEntry();
// size is now available
System.out.println("after " + firstEntry.getSize()); // prints the size

或阅读整个条目数据:

// position at the start of the first entry
entry = zipIn.getNextEntry();
// size is not yet available
System.out.println("before " + entry.getSize()); // prints -1

// read the whole entry data
while(zipIn.read() != -1);

// size is now available
System.out.println("after " + entry.getSize()); // prints the size

您的误解很常见,有很多关于此问题的错误报告(关闭为“非问题”),如JDK-4079029JDK-4113731JDK-6491622

如错误报告中所述,您可以使用ZipFile代替ZipInputStream,这样可以在访问条目数据之前获取尺寸信息;但要创建ZipFile,您需要File(请参阅构造函数)而不是字节数组。

例如:

File file = new File( "test.zip" );
ZipFile zipFile = new ZipFile(file);

Enumeration enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
    ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
    System.out.println(zipEntry.getSize()); // prints the size
}

如何从输入流中获取数据?

如果要检查解压缩的数据是否与原始输入数据相同,您可以像这样读取输入流:

byte[] output = new byte[input.length];
entry = zipIn.getNextEntry();
zipIn.read(output);

System.out.println("Are they equal? " + Arrays.equals(input, output));

// and if we want the size
zipIn.getNextEntry(); // or zipIn.read();
System.out.println("and the size is " + entry.getSize());

现在output应与input具有相同的内容。

答案 1 :(得分:0)

如何压缩byte[]并将其解压缩回来?

我经常使用以下方法来缩小/膨胀(压缩/解压缩)小byte[](即当它适合内存时)。它基于example given in the Deflater javadoc并使用Deflater类来压缩数据,使用Inflater类来解压缩它:

public static byte[] compress(byte[] source, int level) {
    Deflater compresser = new Deflater(level);
    compresser.setInput(source);
    compresser.finish();
    byte[] buf = new byte[1024];
    ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
    int n;
    while ((n = compresser.deflate(buf)) > 0)
        bos.write(buf, 0, n);
    compresser.end();
    return bos.toByteArray(); // You could as well return "bos" directly
}

public static byte[] uncompress(byte[] source) {
    Inflater decompresser = new Inflater();
    decompresser.setInput(source);
    byte[] buf = new byte[1024];
    ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
    try {
        int n;
        while ((n = decompresser.inflate(buf)) > 0)
            bos.write(buf, 0, n);
        return bos.toByteArray();
    } catch (DataFormatException e) {
        return null;
    } finally {
        decompresser.end();
    }
}

不需要ByteArrayInputStream,但您可以使用InflaterInputStream包装它,如果您真的想要(但直接使用Inflater更容易)。