Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何创建多部分zip文件并将其读回?_Java_Zip_Bytearrayoutputstream_Zipoutputstream_Bytearrayinputstream - Fatal编程技术网

Java 如何创建多部分zip文件并将其读回?

Java 如何创建多部分zip文件并将其读回?,java,zip,bytearrayoutputstream,zipoutputstream,bytearrayinputstream,Java,Zip,Bytearrayoutputstream,Zipoutputstream,Bytearrayinputstream,如何正确地将字节压缩到ByteArrayInputStream中,然后使用ByteArrayInputStream读取该字节?我有以下方法: private byte[] getZippedBytes(final String fileName, final byte[] input) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ZipOutputStream zipOut

如何正确地
字节压缩到
ByteArrayInputStream
中,然后使用
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
-1
。我不明白为什么提取的实体与压缩的实体不匹配。

为什么大小为-1?

在要读取的条目的开始处调用读取光标的正确位置

大小(以及其他元数据)存储在实际数据的末尾,因此当光标位于起始位置时,不容易获得

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

例如,转到下一个条目:

// 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
你的误解很常见,关于这个问题有很多bug报告(以“非问题”结尾),比如,

正如bug报告中提到的,您可以使用,而不是允许在访问条目数据之前访问大小信息;但是要创建一个数组,您需要一个(参见构造函数)而不是一个字节数组

例如:

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());
现在,
输出
应该与
输入
具有相同的内容

如何压缩
字节[]
并将其解压缩回来? 我通常使用以下方法对小的
字节[]
(即当它适合内存时)进行放气/充气(压缩/解压)。它基于,并使用类压缩数据,使用类解压缩数据:

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
,但如果您真的愿意,您可以使用包装(但直接使用
充气机更容易)。

为什么?你已经有字节了。为什么你想要压缩和解压它们只是为了找回你已经拥有的东西?这只是一个示例,作为概念证明。在我的实际场景中,我正在使用压缩文件的字节创建一个模拟多部分文件,以便测试另一个类是否正确解压缩内容。bos.toByteArray()的大小是多少?显然,使用
ZipInputStream#closeEntry()
ZipInputStream#getNextEntry()
的效果与
ZipEntry#getSize()相同
与此有关。在任何情况下,上述两种方法都不允许调用前一个条目的数据。@RavindraHV如果您仔细想想,这是非常合乎逻辑的:根据
closeEntry()
:“关闭当前ZIP条目并定位流以读取下一个条目。”这实际上对我来说意味着(基于我对ZIP布局的有限知识)必须将条目读入黑洞才能“关闭”它。在这种情况下,他们可能利用了
getNextEntry()
closeEntry()中的一些常用功能
,而该公共功能反过来设置上一条记录的
大小。对于那些想再次投票而不评论如何改进答案(这并不违法)的人,问题是“如何通过TearrayOutputStream将字节压缩到
并返回”,而不是“如何使用
ZipFile
”为了实现压缩。标题可能应该被编辑(稍后我会找到更好的),但手头的问题是在解压时阅读
ZipEntry
详细信息。你的答案没有解决这个问题。@SotiriosDelimanolis感谢你的反馈。对我来说,这个标题听起来不错,但
ZipEntry
是实现它的错误工具,因此我的答案。但再次感谢你让我有机会解释我自己:)根据更新4,
Deflater
(和
充气机
)有自己的问题。@D.Kovács感谢链接。OpenJDK bug中给出的解决方法是调用
Deflater/Inflater.end()
,上面的代码就是这样做的。