【问题标题】:Java Zip File Created With ByteArrayOutputStream is smaller than with FileOutputStream使用 ByteArrayOutputStream 创建的 Java Zip 文件小于使用 FileOutputStream 创建的
【发布时间】:2020-04-26 21:39:20
【问题描述】:

使用 ByteArrayOuputStream 输出的 Zip 文件比使用 FileOutputStream 小。

在 Java 中,我正在创建一个 Zip 文件。当我使用 FileOutputStream 时,它会成功打开。

将 FileOutputStream 切换到 ByteArrayOutputStream 时,我得到一个稍微小一点的文件,大约 221 个字节。而且这个文件不会打开,但是和另一个文件的内容相同,但是少了 221 个字节。

我用于构建 Zip 文件的逻辑在这两种情况下都是相同的。因此,我将在不创建 zip 的情况下分享基本逻辑(如果您需要,请告诉我)。

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        zipOS = new ZipOutputStream(baos);

然后我创建 Zip 文件,然后...

        zipOS.flush();
        baos.flush();
        baos.writeTo(new FileOutputStream("TEST_AS_BYTESTREAM_1.zip"));
        zipOS.close();
        baos.close();

我正在使用 baos.writeTo() 绕过这个以证明问题不是 HTTP 响应而是 ByteArrayOutputStream 元素。

当使用baos.writeTo(new FileOutputStream("TEST_AS_BYTESTREAM_1.zip")); 我得到一个不以 Zip 格式打开的较小文件。

这个逻辑在 java 控制器中,因此点击网页上的链接将下载 zip 文件,而不会触及除用户之外的任何文件系统。

这是使用 FileOutputStream 的代码...

        FileOutputStream baos = new FileOutputStream("TEST_AS_FILE.zip");
        zipOS = new ZipOutputStream(baos);

除了第二个代码 sn-p 不相关,因为我需要发送在 Web 服务器上创建的文件。但重点是,同样逻辑的Fileoutput流和ByteArrayOutputStream是有区别的。

【问题讨论】:

  • 你应该关闭zipOS之前获取baos的内容。

标签: java zip fileoutputstream bytearrayoutputstream


【解决方案1】:

以下说法错误:

baos.writeTo(new FileOutputStream("TEST_AS_BYTESTREAM_1.zip"));

writeTo(OutputStream out) 的 javadoc 没有说明关闭 OutputStream,这意味着它没有,因此最后的数据仍然缓冲在未关闭、未刷新的 FileOutputStream 中。

正确的做法是:

try (OutputStream out = new FileOutputStream("TEST_AS_BYTESTREAM_1.zip")) {
    baos.writeTo(out);
}

另外,ByteArrayOutputStream 不需要关闭或刷新。正如close() 的 javadoc 所说:

关闭ByteArrayOutputStream 无效。

但是,您需要在 ZipOutputStream 上致电 finish() 以完成内容。由于关闭 zip 流会自动为您完成,因此正确的做法是:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zipOS = new ZipOutputStream(baos)) {
    // create the Zip file content here
}
try (OutputStream out = new FileOutputStream("TEST_AS_BYTESTREAM_1.zip")) {
    baos.writeTo(out);
}

直接写入文件时:

try (ZipOutputStream zipOS = new ZipOutputStream(new FileOutputStream("TEST_AS_FILE.zip"))) {
    // create the Zip file content here
}

考虑添加BufferedOutputStream 以获得更好的性能。

【讨论】:

  • 谢谢,我唯一需要做的就是在 zip 输出流上添加 .finish() 调用。将在下面分享答案。
【解决方案2】:

最终答案如下。非常感谢之前给出的答案。

基本上我需要使用 ZipOuputStream 的 .finish() 方法。其他一切都保持不变。

Pre zip 创建代码与之前相同

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        zipOS = new ZipOutputStream(baos);

发布 zip 创建...

        zipOS.flush();
        zipOS.finish();
        baos.flush();
        documentBody = baos.toByteArray();
        zipOS.close();
        baos.close();

那么我的 HTTP 响应是

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(new MediaType("application", "zip"));
    headers.setContentLength(documentBody.length);
    headers.add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
    ByteArrayResource resource = new ByteArrayResource(documentBody);

    return ResponseEntity.ok()
            .headers(headers)
            .body(resource);

这样我可以避免创建一个很好的文件。

非常感谢您的帮助。

【讨论】:

  • 对我有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 2013-07-03
相关资源
最近更新 更多