1

I've followed several articles to create a zip file using java ZipOutputStream class. The zip is created but I cannot open it. On my Mac I'm receiving this message when I open it with the unzip command :

End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive. In the latter case the central directory and zipfile comment will be found on the last disk(s) of this archive.

unzip: cannot find zipfile directory in one of /Users/xxxx/Downloads/iad.zip or
/Users/xxxx/Downloads/iad.zip.zip, and cannot find /Users/xxxx/Downloads/iad.zip.ZIP, period.

My java class :

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static java.util.Arrays.stream;

@Slf4j
@UtilityClass
public class ZipCreator {

    public byte[] compressAll(String... files) throws IOException {

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ZipOutputStream zipOut = new ZipOutputStream(baos)) {

            stream(files)
                    .forEach(file -> addToZip(zipOut, file));

            return baos.toByteArray();
        }
    }

    private static void addToZip(ZipOutputStream zipOut, String file) {
        File fileToZip = new File(file);
        try (FileInputStream fis = new FileInputStream(fileToZip.getCanonicalFile())) {
            zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));

            byte[] bytes = new byte[1024];
            int length;
            while ((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }
        } catch (IOException e) {
            log.error("Error when adding file {} to zip", file, e);
        }
    }
}

Doas anyone have an idea to get this zip open ?

bubbles
  • 2,597
  • 1
  • 15
  • 40

1 Answers1

5

You forgot to call closeEntry(). And you should call close() for ZipOutputStream before baos.toByteArray():

public static byte[] compressAll(String... files) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (ZipOutputStream zipOut = new ZipOutputStream(baos)) {
        stream(files).forEach(file -> addToZip(zipOut, file));
    }
    return baos.toByteArray();
}

private static void addToZip(ZipOutputStream zipOut, String file) {
    File fileToZip = new File(file);
    try (FileInputStream fis = new FileInputStream(fileToZip.getCanonicalFile())) {
        zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));

        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }

        zipOut.closeEntry();
    } catch (IOException e) {
        log.error("Error when adding file {} to zip", file, e);
    }
}

For ByteArrayOutputStream you must close ZipOutputStream before retrieve byte array from ByteArrayOutputStream. For FileOutputStream is the same. You must close ZipOutputStream before closing FileOutputStream. Note that the close methods of resources are called in the opposite order of their creation.

public static void compressAll(String... files) throws IOException {
    try (FileOutputStream fos = new FileOutputStream("test.zip");
         ZipOutputStream zipOut = new ZipOutputStream(fos)) {
        stream(files).forEach(file -> addToZip(zipOut, file));
    }
}
User9123
  • 1,643
  • 1
  • 8
  • 21
  • `zipOut.close() ` isn't closed by the try-ressource ? – bubbles Mar 18 '20 at 19:26
  • 1
    Fix answer. You should close ZipOutputStream before baos.toByteArray(). And ByteArrayOutputStream has empty close method – User9123 Mar 18 '20 at 19:44
  • So when you close ´baos´ ? – bubbles Mar 18 '20 at 21:00
  • 1
    ByteArrayOutputStream not needed to close. It has empty close method. You can do it but it makes no sense. See this for more info: https://stackoverflow.com/questions/2330569/closing-a-bytearrayoutputstream-has-no-effect – User9123 Mar 18 '20 at 21:06
  • append answer for FileOutputStream – User9123 Mar 19 '20 at 09:49
  • in fact I just tried your first solution, it's not working. I get the same error when I open the zip – bubbles Mar 19 '20 at 10:36
  • How do you create your file from byte array? Do you catch exception in "Error when adding file {} to zip"? – User9123 Mar 19 '20 at 11:14
  • 1
    finally I just had to add `zipOut.finish();` before `baos.toByteArray()` in my code (question version) to get it works. – bubbles Mar 19 '20 at 13:46