Vaibhav Aggarwal
Vaibhav Aggarwal

Reputation: 1411

Convert Zip to Store compression

I have a zip file file.zip that is compressed. Is there a way to change the compression level of the file to store (no compression).

I have written and tried the following code and it works, but I will be running this in an environment where memory and storage will be a limitation and there might not be enough space. I am using the zip4j library.

This code extracts the input zip to a folder, then rezips it with store compression level. The problem with this is that at one point in execution, there are 3 copies of the zip on storage, which is a problem because space is a limitation.

try {
            String zip = "input.zip";
            final ZipFile zipFile = new ZipFile(zip);
            zipFile.extractAll("dir");
            File file = new File("dir");
            ZipParameters params = new ZipParameters();
            params.setCompressionMethod(Zip4jConstants.COMP_STORE);
            params.setIncludeRootFolder(false);

            ZipFile output = new ZipFile(new File("out.zip"));

            output.addFolder(file, params);
            file.delete();
            return "Done";
        } catch (Exception e) {
            e.printStackTrace();
            return "Error";
        }

So any suggestions on another way to approach this problem? Or maybe some speed or memory optimizations to my current code?

Upvotes: 3

Views: 1507

Answers (2)

Vaibhav Aggarwal
Vaibhav Aggarwal

Reputation: 1411

I finally got it after a few hours by playing around with input streams.

try {
            final ZipFile zipFile = new ZipFile("input.zip");
            File output = new File("out.zip");
            byte[] read = new byte[1024];
            ZipInputStream zis = new ZipInputStream(new FileInputStream(zip));
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output));
            ZipEntry ze;
            zos.setLevel(ZipOutputStream.STORED);
            zos.setMethod(ZipOutputStream.STORED);
            while((ze = zis.getNextEntry()) != null) {
                int l;
                zos.putNextEntry(ze);
                System.out.println("WRITING:  " + ze.getName());
                while((l = zis.read(read)) > 0) {
                    zos.write(read, 0, l);
                }
                zos.closeEntry();
            }
            zis.close();
            zos.close();
            return "Done";
        } catch (Exception e) {
            e.printStackTrace();
            return "Error";
        }

Thanks so much for your answer Evgeniy Dorofeev, I literally just got my answer when I read yours! However, I prefer my method as it only takes up a maximum of 1 MB in memory (Am I right?). Also, I tried executing your code and only the first file in the input zip was transferred.

Upvotes: 0

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136012

As an alternative we can read files from zip one by one in memory or into temp file, like here

    ZipInputStream is = ...
    ZipOutputStream os = ...
    os.setMethod(ZipOutputStream.STORED);
    int bSize = ... calculate max available size 
    byte[] buf = new byte[bSize];
    for (ZipEntry e; (e = is.getNextEntry()) != null;) {
        ZipEntry e2 = new ZipEntry(e.getName());
        e2.setMethod(ZipEntry.STORED);
        int n = is.read(buf);
        if (is.read() == -1) {
            // in memory
            e2.setSize(n);
            e2.setCompressedSize(n);
            CRC32 crc = new CRC32();
            crc.update(buf, 0, n);
            e2.setCrc(crc.getValue());
            os.putNextEntry(e2);
            os.write(buf, 0, n);
            is.closeEntry();
            os.closeEntry();
        } else {
            // use tmp file
        }
    }

reading in memory is supposed to be faster

Upvotes: 1

Related Questions