Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unzip files recursively in Java?

Tags:

java

unzip

People also ask

Is unzip recursive?

The unzip command doesn't have an option for recursively unzipping archives. What command or commands would I issue? It's important that this doesn't choke on filenames that have spaces in them.

How can I read the content of a zip file without unzipping it in Java?

Methods. getComment(): String – returns the zip file comment, or null if none. getEntry(String name): ZipEntry – returns the zip file entry for the specified name, or null if not found. getInputStream(ZipEntry entry) : InputStream – Returns an input stream for reading the contents of the specified zip file entry.

Can you open a zip file in Java if yes then how?

To unzip a zip file, we need to read the zip file with ZipInputStream and then read all the ZipEntry one by one. Then use FileOutputStream to write them to file system. We also need to create the output directory if it doesn't exists and any nested directories present in the zip file.


Warning, the code here is ok for trusted zip files, there's no path validation before write which may lead to security vulnerability as described in zip-slip-vulnerability if you use it to deflate an uploaded zip file from unknown client.


This solution is very similar to the previous solutions already posted, but this one recreates the proper folder structure on unzip.

public static void extractFolder(String zipFile) throws IOException {
int buffer = 2048;
File file = new File(zipFile);

try (ZipFile zip = new ZipFile(file)) {
  String newPath = zipFile.substring(0, zipFile.length() - 4);

  new File(newPath).mkdir();
  Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();

  // Process each entry
  while (zipFileEntries.hasMoreElements()) {
    // grab a zip file entry
    ZipEntry entry = zipFileEntries.nextElement();
    String currentEntry = entry.getName();
    File destFile = new File(newPath, currentEntry);
    File destinationParent = destFile.getParentFile();

    // create the parent directory structure if needed
    destinationParent.mkdirs();

    if (!entry.isDirectory()) {
      BufferedInputStream is = new BufferedInputStream(zip.getInputStream(entry));
      int currentByte;
      // establish buffer for writing file
      byte[] data = new byte[buffer];

      // write the current file to disk
      FileOutputStream fos = new FileOutputStream(destFile);
      try (BufferedOutputStream dest = new BufferedOutputStream(fos, buffer)) {

        // read and write until last byte is encountered
        while ((currentByte = is.read(data, 0, buffer)) != -1) {
          dest.write(data, 0, currentByte);
        }
        dest.flush();
        is.close();
      }
    }

    if (currentEntry.endsWith(".zip")) {
      // found a zip file, try to open
      extractFolder(destFile.getAbsolutePath());
    }
  }
}

}


Here's some untested code base on some old code I had that unzipped files.

public void doUnzip(String inputZip, String destinationDirectory)
        throws IOException {
    int BUFFER = 2048;
    List zipFiles = new ArrayList();
    File sourceZipFile = new File(inputZip);
    File unzipDestinationDirectory = new File(destinationDirectory);
    unzipDestinationDirectory.mkdir();

    ZipFile zipFile;
    // Open Zip file for reading
    zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);

    // Create an enumeration of the entries in the zip file
    Enumeration zipFileEntries = zipFile.entries();

    // Process each entry
    while (zipFileEntries.hasMoreElements()) {
        // grab a zip file entry
        ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();

        String currentEntry = entry.getName();

        File destFile = new File(unzipDestinationDirectory, currentEntry);
        destFile = new File(unzipDestinationDirectory, destFile.getName());

        if (currentEntry.endsWith(".zip")) {
            zipFiles.add(destFile.getAbsolutePath());
        }

        // grab file's parent directory structure
        File destinationParent = destFile.getParentFile();

        // create the parent directory structure if needed
        destinationParent.mkdirs();

        try {
            // extract file if not a directory
            if (!entry.isDirectory()) {
                BufferedInputStream is =
                        new BufferedInputStream(zipFile.getInputStream(entry));
                int currentByte;
                // establish buffer for writing file
                byte data[] = new byte[BUFFER];

                // write the current file to disk
                FileOutputStream fos = new FileOutputStream(destFile);
                BufferedOutputStream dest =
                        new BufferedOutputStream(fos, BUFFER);

                // read and write until last byte is encountered
                while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
                    dest.write(data, 0, currentByte);
                }
                dest.flush();
                dest.close();
                is.close();
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
    zipFile.close();

    for (Iterator iter = zipFiles.iterator(); iter.hasNext();) {
        String zipName = (String)iter.next();
        doUnzip(
            zipName,
            destinationDirectory +
                File.separatorChar +
                zipName.substring(0,zipName.lastIndexOf(".zip"))
        );
    }

}

I take ca.anderson4 and remove the List zipFiles and rewrite a little bit, this is what i got:

public class Unzip {

public void unzip(String zipFile) throws ZipException,
        IOException {

    System.out.println(zipFile);;
    int BUFFER = 2048;
    File file = new File(zipFile);

    ZipFile zip = new ZipFile(file);
    String newPath = zipFile.substring(0, zipFile.length() - 4);

    new File(newPath).mkdir();
    Enumeration zipFileEntries = zip.entries();

    // Process each entry
    while (zipFileEntries.hasMoreElements()) {
        // grab a zip file entry
        ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();

        String currentEntry = entry.getName();

        File destFile = new File(newPath, currentEntry);
        destFile = new File(newPath, destFile.getName());
        File destinationParent = destFile.getParentFile();

        // create the parent directory structure if needed
        destinationParent.mkdirs();
        if (!entry.isDirectory()) {
            BufferedInputStream is = new BufferedInputStream(zip
                    .getInputStream(entry));
            int currentByte;
            // establish buffer for writing file
            byte data[] = new byte[BUFFER];

            // write the current file to disk
            FileOutputStream fos = new FileOutputStream(destFile);
            BufferedOutputStream dest = new BufferedOutputStream(fos,
                    BUFFER);

            // read and write until last byte is encountered
            while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
                dest.write(data, 0, currentByte);
            }
            dest.flush();
            dest.close();
            is.close();
        }
        if (currentEntry.endsWith(".zip")) {
            // found a zip file, try to open
            unzip(destFile.getAbsolutePath());
        }
    }
}

public static void main(String[] args) {
    Unzip unzipper=new Unzip();
    try {
        unzipper.unzip("test/test.zip");
    } catch (ZipException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

I tested and it works


In testing I noticed File.mkDirs() does not work under Windows...

/** * for a given full path name recreate all parent directories **/

    private void createParentHierarchy(String parentName) throws IOException {
        File parent = new File(parentName);
        String[] parentsStrArr = parent.getAbsolutePath().split(File.separator == "/" ? "/" : "\\\\");

        //create the parents of the parent
        for(int i=0; i < parentsStrArr.length; i++){
            StringBuffer currParentPath = new StringBuffer();
            for(int j = 0; j < i; j++){
                currParentPath.append(parentsStrArr[j]+File.separator);
            }
            File currParent = new File(currParentPath.toString());
            if(!currParent.isDirectory()){
                boolean created = currParent.mkdir();
                if(isVerbose)log("creating directory "+currParent.getAbsolutePath());
            }
        }

        //create the parent itself
        if(!parent.isDirectory()){
            boolean success = parent.mkdir();
        }
    }

Modified as i needed then mixed in a bit of the best answers. This version will:

  • Recursively Extract a zip to given location

  • Create empty directories

  • Close zip properly


public static void unZipAll(File source, File destination) throws IOException 
{
    System.out.println("Unzipping - " + source.getName());
    int BUFFER = 2048;

    ZipFile zip = new ZipFile(source);
    try{
        destination.getParentFile().mkdirs();
        Enumeration zipFileEntries = zip.entries();

        // Process each entry
        while (zipFileEntries.hasMoreElements())
        {
            // grab a zip file entry
            ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
            String currentEntry = entry.getName();
            File destFile = new File(destination, currentEntry);
            //destFile = new File(newPath, destFile.getName());
            File destinationParent = destFile.getParentFile();

            // create the parent directory structure if needed
            destinationParent.mkdirs();

            if (!entry.isDirectory())
            {
                BufferedInputStream is = null;
                FileOutputStream fos = null;
                BufferedOutputStream dest = null;
                try{
                    is = new BufferedInputStream(zip.getInputStream(entry));
                    int currentByte;
                    // establish buffer for writing file
                    byte data[] = new byte[BUFFER];

                    // write the current file to disk
                    fos = new FileOutputStream(destFile);
                    dest = new BufferedOutputStream(fos, BUFFER);

                    // read and write until last byte is encountered
                    while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
                        dest.write(data, 0, currentByte);
                    }
                } catch (Exception e){
                    System.out.println("unable to extract entry:" + entry.getName());
                    throw e;
                } finally{
                    if (dest != null){
                        dest.close();
                    }
                    if (fos != null){
                        fos.close();
                    }
                    if (is != null){
                        is.close();
                    }
                }
            }else{
                //Create directory
                destFile.mkdirs();
            }

            if (currentEntry.endsWith(".zip"))
            {
                // found a zip file, try to extract
                unZipAll(destFile, destinationParent);
                if(!destFile.delete()){
                    System.out.println("Could not delete zip");
                }
            }
        }
    } catch(Exception e){
        e.printStackTrace();
        System.out.println("Failed to successfully unzip:" + source.getName());
    } finally {
        zip.close();
    }
    System.out.println("Done Unzipping:" + source.getName());
}