0

Our external application sends the zip file name and content as two strings in the response to an API call. I converted the string to bytearray and used zipinputstream to read the bytearray. If the zip file contains only one file, I am able to read the string and extract the zipped file contents into a separate string. Below is the code snippet I used to extract the file content.

If the zipped file contains more than one file and the entire zipped content is sent as a single string, how do I extract individual file contents into separate strings? How to identify the end of each file in the string?

byte[] data = Base64Util.decodeToByteArray(ZipString);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(bais));
ZipEntry ze = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b =  new byte[4096];
String ZippedFileName = new String();
String ZippedFileData = new String();

try 
{
 while((ze = zin.getNextEntry()) != null)
 {
    ZippedFileName = ze.getName();
    while((zin.read(b,0,4096))!= -1)
    {
        baos.write(b,0,4096);
    }
 }
 byte[] out = baos.toByteArray();
 ZippedFileData = Base64Util.encodeToString(out);
 zin.close();
 bais.close();
 baos.close();
}

catch(Exception Ex)
{
    Ex.toString();
}
  • Each time you call `getNextEntry()`, you are reading a different entry in the zip. One of those entries contains data which is one of your strings; another one of those entries is your other string. Test the value returned by `ze.getName()` to determine which entry is which. – VGR Sep 06 '22 at 23:41
  • I tried this with a zip file containing three files (word, pdf and jpg files). When the entire zip file content is represented as string, getNextEntry() only gives the first file name correctly. After that, it gives another file name as contents.xml. It is not reading the other two files. – Sathish Kumar Sep 07 '22 at 00:09
  • *When the entire zip file content is represented as string, getNextEntry() only gives the first file name...* Actually it's not the content as string that seems to be the problem - it's that the whole zip file has come not from the file system, but from a byte array. I'm having the same problem experimenting with this and it's got me surprised and stumped ;) – g00se Sep 07 '22 at 10:26

1 Answers1

0

Actually I think I was presenting the base64 file in string form incorrectly. For one thing, if line feeds are present in the input, it doesn't like it. If you're working on a Unix based system, you can run the below with something like java Unzip64

"$(cat a.zip | base64 | tr -d '\n')"

The following is working fine for me

import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;
import java.util.Base64;
import java.util.Map;
import java.util.HashMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class Unzip64 {
    public static void main(String[] args) {
        System.out.println(Unzip64.getEntriesAndContents(args[0]));
    }

    public static Map<String, String> getEntriesAndContents(String base64Zip) {
        Map<String, String> result = new HashMap<>();
        try {
            byte[] data = Base64.getDecoder().decode(base64Zip);
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            try (ZipInputStream zin = new ZipInputStream(bais)) {
                ZipEntry ze = null;
                byte[] b = new byte[4096];

                while ((ze = zin.getNextEntry()) != null) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int numRead = -1;
                    String entryName = ze.getName();
                    while ((numRead = zin.read(b, 0, b.length)) > -1) {
                        baos.write(b, 0, numRead);
                    }
                    String entryData = new String(baos.toByteArray());
                    result.put(entryName, entryData);
                    baos = null;
                    zin.closeEntry();
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return result;
    }
}

And here's a sample to run: UEsDBAoAAAgAAKdCJ1UAAAAAAAAAAAAAAAAHAAQAcm9vdC9hL/7KAABQSwMEFAAICAgAp0InVQAAAAAAAAAAAAAAAAwAAAByb290L2EvYS50eHRL5AIAUEsHCAeh6t0EAAAAAgAAAFBLAwQUAAgICACnQidVAAAAAAAAAAAAAAAADAAAAHJvb3QvYS9iLnR4dEviAgBQSwcIxPLH9gQAAAACAAAAUEsDBBQACAgIAKdCJ1UAAAAAAAAAAAAAAAAMAAAAcm9vdC9hL2MudHh0S+YCAFBLBwiFw9zvBAAAAAIAAABQSwECCgAKAAAIAACnQidVAAAAAAAAAAAAAAAABwAEAAAAAAAAAAAAAAAAAAAAcm9vdC9hL/7KAABQSwECFAAUAAgICACnQidVB6Hq3QQAAAACAAAADAAAAAAAAAAAAAAAAAApAAAAcm9vdC9hL2EudHh0UEsBAhQAFAAICAgAp0InVcTyx/YEAAAAAgAAAAwAAAAAAAAAAAAAAAAAZwAAAHJvb3QvYS9iLnR4dFBLAQIUABQACAgIAKdCJ1WFw9zvBAAAAAIAAAAMAAAAAAAAAAAAAAAAAKUAAAByb290L2EvYy50eHRQSwUGAAAAAAQABADnAAAA4wAAAAAA

g00se
  • 3,207
  • 2
  • 5
  • 9