简体   繁体   中英

Java Zip File Created With ByteArrayOutputStream is smaller than with FileOutputStream

The Zip file output from using ByteArrayOuputStream is smaller than that with FileOutputStream.

In Java I am creating a Zip file. Which opens successfully when I use FileOutputStream.

When switching the FileOutputStream to a ByteArrayOutputStream I get a slightly smaller file, about 221 bytes. And this file won't open, but has the same contents as the other but missing 221 bytes.

The logic I use to construct the Zip file is the same in both cases. Therefore I will share the essential logic without the zip creation (let me know if you need this).

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

Then I create the Zip file, and then ...

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

I'm using the baos.writeTo() to bypass this to prove it's not the HTTP response but the ByteArrayOutputStream element thats an issue.

When using baos.writeTo(new FileOutputStream("TEST_AS_BYTESTREAM_1.zip")); I get a smaller file that doesn't open as a Zip.

This logic is in a java controller so that a link clicked on web page will down load the zip file without touching any file systems excepted the users.

Here is the code using FileOutputStream which works...

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

Aside from the the second code snippet isn't relevant as I would need to send the file created on the web server. But the point is, that Fileoutput stream with the same logic and ByteArrayOutputStream has a difference.

The following statement is wrong:

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

The javadoc of writeTo(OutputStream out) does not say anything about closing the OutputStream , which means it doesn't, so the last of the data is still sitting buffered in the un-closed, un-flushed FileOutputStream .

The correct way is:

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

Also, a ByteArrayOutputStream does not need to be closed or flushed. As the javadoc of close() says it:

Closing a ByteArrayOutputStream has no effect.

You will however need to call finish() on an ZipOutputStream to complete the content. Since closing the zip stream automatically finishes it for you, the correct way to do this is:

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

When writing directly to a file:

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

Consider adding a BufferedOutputStream for better performance.

The final answer is as follows. Many thanks to the answer previously given.

Basically I needed to use the .finish() method of the ZipOuputStream. Everything else remained the same.

Pre zip creation code same as before

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

Post zip creation...

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

Then my HTTP response is

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

This way I avoid the creation of a file which is nice.

Many thanks for the assistance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM