Java 使用 ByteArrayOutputStream 创建的 Zip 文件小于使用 FileOutputStream 创建的 Zip 文件

Java Zip File Created With ByteArrayOutputStream is smaller than with FileOutputStream

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

在 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 控制器中,因此 link 单击网页将下载 zip 文件,而不会触及除用户以外的任何文件系统。

这是使用 FileOutputStream 的有效代码...

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

除此之外,第二个代码片段不相关,因为我需要发送在网络服务器上创建的文件。但关键是,同样逻辑的Fileoutput流和ByteArrayOutputStream是有区别的。

下列说法错误的是:

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 does not need to be closed or flushed. As the javadoc of close()说:

Closing a ByteArrayOutputStream has no effect.

不过,您需要致电 finish() on an ZipOutputStream 才能完成内容。由于关闭 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 以获得更好的性能。

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

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

压缩前创建代码与之前相同

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

Post 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);

这样我就避免了创建一个很好的文件。

非常感谢您的帮助。