【问题标题】:Corrupted zip file using ZipOutputStream使用 ZipOutputStream 损坏的 zip 文件
【发布时间】:2020-08-24 15:06:27
【问题描述】:

我正在尝试创建一个 zip 文件,以便能够通过 http 发送多个文件。

我的问题是生成的 Zip 文件在文件发送前后“损坏”。问题是我无法找到我做错了什么,因为我在控制台中没有收到任何错误。

那么有人知道我生成的 zip 文件损坏了吗?

这是我的代码:

  OutputStream responseBody = t.getResponseBody();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);


            int counter = 1;
            for (PDDocument doc : documents)
            {
                ZipEntry zipEntry = new ZipEntry("document" + counter);
                zos.putNextEntry(zipEntry);
                ByteArrayOutputStream docOs = new ByteArrayOutputStream();
                doc.save(docOs);
                docOs.close();
                zos.write(docOs.toByteArray());
                zos.closeEntry();
                zos.finish();
                zos.flush();

                counter++;
            }
            zos.close();
            baos.close();


            responseBody.write(baos.toByteArray());
            responseBody.flush();

感谢您的帮助!

【问题讨论】:

  • 如果您的目标是发送多个文件而不是专门压缩,您可以使用 multipart/form-data,可能使用部分压缩。

标签: java zipoutputstream


【解决方案1】:

您需要从循环内部删除 zos.finish(),因为它会终止 ZIP 条目,因为它由流末尾的 zos.close() 处理。

对于非常大的流,最好绕过ByteArrayOutputStream 内存缓冲区直接将 ZIP 发送到 responseBody。

如果您仍然遇到问题,请检查输出的内容类型是否已设置。通过临时将 byte[] 写入文件以检查您发送的 ZIP 格式可能更容易调试:

Files.write(Path.of("temp.zip"), baos.toByteArray());

下面的大纲显示了通过 http 发送一个简单的 ZIP(从一个 servlet,调整前 2 行以适当地调用“t”)。如果您重新在循环中添加自己的文档对象,这可能会帮助您检查代码的哪个步骤导致损坏:

// MUST set response content type:
// resp.setContentType("application/zip");
OutputStream out = resp.getOutputStream(); // or t.getResponseBody();
try(ZipOutputStream zos = new ZipOutputStream(out))
{
    while (counter-- > 0)
    {
        ZipEntry zipEntry = new ZipEntry("document" + counter+".txt");
        zos.putNextEntry(zipEntry);
        zos.write(("This is ZipEntry: "+zipEntry.getName()+"\r\n").getBytes());
    }
}

【讨论】:

  • 即使经过这些修改,zip 仍然损坏@DuncG
  • 如果 zos.finish() 在循环内,则 ZIP 将只包含第一个条目。
  • @MichelMelhem DuncG 绝对正确,您需要摆脱每一个 ByteArrayOutputStream。您正在扼杀程序的性能!只需将响应的输出正文包装在 ZipOutputStream 中并直接写入即可。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多