Antonio Dragos
Antonio Dragos

Reputation: 2813

why does extraction of this ZIP archive fail?

I've written the following method to create a ZIP archive

public class ZipUtils {
    public static byte[] createZipArchive(Collection<FileWrapper> sourceFiles) throws IOException {

        try (var bytesOut = new ByteArrayOutputStream(); var zipOut = new ZipOutputStream(bytesOut)) {

            for (var sourceFile : sourceFiles) {
                try (var fileContent = sourceFile.getResource().getInputStream()) {

                    var zipEntry = new ZipEntry(sourceFile.getFileName());
                    zipOut.putNextEntry(zipEntry);

                    byte[] bytes = new byte[1024];
                    int length;
                    while ((length = fileContent.read(bytes)) >= 0) {
                        zipOut.write(bytes, 0, length);
                    }
                }
            }
            zipOut.flush();
            return bytesOut.toByteArray();
        }
    }
}

FileWrapper is a simple data class that encapsulates a file's content and it's name

import org.springframework.core.io.Resource;

public class FileWrapper {
    private final String fileName;
    private final Resource resource;

    // getters, setters, constructors omitted
}

I've written the following unit test

public class ZipUtilsTests {

    @Test
    void createZipArchive() throws IOException {
        var file1 = getFile("src/test/resources/json/event.json");
        var file2 = getFile("src/test/resources/json/label.json");
        var zipData = ZipUtils.createZipArchive(Set.of(file1, file2));

        File zipOutput = File.createTempFile("2-json-files", ".zip");
        logger.debug("Writing ZIP archive to: " + zipOutput.getAbsolutePath());
        Files.write(zipOutput.toPath(), zipData);
    }

    private FileWrapper getFile(String path) throws IOException {
        var bytes = Files.readAllBytes(Paths.get(path));
        var resource = new ByteArrayResource(bytes);
        var fileName = StringUtils.substringAfterLast(path, '/');
        return new FileWrapper(fileName, resource);
    }
}

If I navigate to the ZIP file this test creates and try to unzip it, I get the following error

enter image description here

The size of the file is roughly what I would expect, but there's obviously something wrong with it because extraction of the files fails.

Upvotes: 1

Views: 151

Answers (2)

Jose Antonio Torralba
Jose Antonio Torralba

Reputation: 26

try this:

try(var bytesOut = new ByteArrayOutputStream()) { 
        
    try (var zipOut = new ZipOutputStream(bytesOut)) {
        for (var sourceFile : sourceFiles) {
            try (var fileContent = sourceFile.getResource().getInputStream()) {

                var zipEntry = new ZipEntry(sourceFile.getFileName());
                zipOut.putNextEntry(zipEntry);

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

You need that zipOut is closed before you return byte array.

I hope help you

Upvotes: 1

Issa Khodadadi
Issa Khodadadi

Reputation: 1104

just add:

zipOut.closeEntry();
zipOut.close();

before return bytesOut.toByteArray();

Done.

Upvotes: 1

Related Questions