Question

I am using the following code to extract a zip file in Java.

import java.io.*;
import java.util.zip.*;

class  testZipFiles 
{
    public static void main(String[] args) 
    {

        try
        {
            String filename = "C:\\zip\\includes.zip";
            testZipFiles list = new testZipFiles( );
            list.getZipFiles(filename);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void getZipFiles(String filename)
    {
        try
        {
            String destinationname = "c:\\zip\\";
            byte[] buf = new byte[1024];
            ZipInputStream zipinputstream = null;
            ZipEntry zipentry;
            zipinputstream = new ZipInputStream(
            new FileInputStream(filename));

            zipentry = zipinputstream.getNextEntry();
            while (zipentry != null) 
            { 
                //for each entry to be extracted
                String entryName = zipentry.getName();
                System.out.println("entryname "+entryName);
                int n;
                FileOutputStream fileoutputstream;
                File newFile = new File(entryName);
                String directory = newFile.getParent();

                if(directory == null)
                {
                    if(newFile.isDirectory())
                    break;
                }

                fileoutputstream = new FileOutputStream(
                   destinationname+entryName);             

                while ((n = zipinputstream.read(buf, 0, 1024)) > -1)
                    fileoutputstream.write(buf, 0, n);

                fileoutputstream.close(); 
                zipinputstream.closeEntry();
                zipentry = zipinputstream.getNextEntry();

            }//while

            zipinputstream.close();
        }
        catch (Exception e)
       {
            e.printStackTrace();
       }
  }

}

Obviously this will not extract a folder tree because of the break statement. I tried to use recursion to process a folder tree but failed. Could someone show me how to improve this code to handle a folder tree instead of a compressed single level folder.

Was it helpful?

Solution

You can use File.mkdirs() to create folders. Try changing your method like this:

public static void getZipFiles(String filename) {
    try {
        String destinationname = "c:\\zip\\";
        byte[] buf = new byte[1024];
        ZipInputStream zipinputstream = null;
        ZipEntry zipentry;
        zipinputstream = new ZipInputStream(
                new FileInputStream(filename));

        zipentry = zipinputstream.getNextEntry();
        while (zipentry != null) {
            //for each entry to be extracted
            String entryName = destinationname + zipentry.getName();
            entryName = entryName.replace('/', File.separatorChar);
            entryName = entryName.replace('\\', File.separatorChar);
            System.out.println("entryname " + entryName);
            int n;
            FileOutputStream fileoutputstream;
            File newFile = new File(entryName);
            if (zipentry.isDirectory()) {
                if (!newFile.mkdirs()) {
                    break;
                }
                zipentry = zipinputstream.getNextEntry();
                continue;
            }

            fileoutputstream = new FileOutputStream(entryName);

            while ((n = zipinputstream.read(buf, 0, 1024)) > -1) {
                fileoutputstream.write(buf, 0, n);
            }

            fileoutputstream.close();
            zipinputstream.closeEntry();
            zipentry = zipinputstream.getNextEntry();

        }//while

        zipinputstream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

OTHER TIPS

Another option is commons-compress, for which there is sample code on the site linked above.

I needed to do this because of an API which I was using required a File parameter, which you can't get from a resource in a JAR.

I found that the answer from @Emre didn't work correctly. For some reason ZipEntry skipped a few files in the JAR (no apparent pattern to this). I fixed this by using JarEntry instead. There is also a bug in the above code where the file in the zip entry could be enumerated before the directory is, which causes an exception because the directory hasn't been created yet.

Note that the below code depends on Apache Commons utility classes.

/**
 * 
 * Extract a directory in a JAR on the classpath to an output folder.
 * 
 * Note: User's responsibility to ensure that the files are actually in a JAR.
 * The way that I do this is to get the URI with
 *     URI url = getClass().getResource("/myresource").toURI();
 * and then if url.isOpaque() we are in a JAR. There may be a more reliable
 * way however, please edit this answer if you know of one.
 * 
 * @param classInJar A class in the JAR file which is on the classpath
 * @param resourceDirectory Path to resource directory in JAR
 * @param outputDirectory Directory to write to  
 * @return String containing the path to the folder in the outputDirectory
 * @throws IOException
 */
private static String extractDirectoryFromClasspathJAR(Class<?> classInJar, String resourceDirectory, String outputDirectory)
        throws IOException {

    resourceDirectory = StringUtils.strip(resourceDirectory, "\\/") + File.separator;

    URL jar = classInJar.getProtectionDomain().getCodeSource().getLocation();
    //Note: If you want to extract from a named JAR, remove the above 
    //line and replace "jar.getFile()" below with the path to the JAR.
    JarFile jarFile = new JarFile(new File(jar.getFile()));

    byte[] buf = new byte[1024];
    Enumeration<JarEntry> jarEntries = jarFile.entries();
    while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = jarEntries.nextElement();

        if (jarEntry.isDirectory() || !jarEntry.getName().startsWith(resourceDirectory)) {
            continue;               
        }


        String outputFileName = FilenameUtils.concat(outputDirectory, jarEntry.getName());
        //Create directories if they don't exist
        new File(FilenameUtils.getFullPath(outputFileName)).mkdirs();

        //Write file
        FileOutputStream fileOutputStream = new FileOutputStream(outputFileName);
        int n;
        InputStream is = jarFile.getInputStream(jarEntry);
        while ((n = is.read(buf, 0, 1024)) > -1) {
            fileOutputStream.write(buf, 0, n);
        }
        is.close();
        fileOutputStream.close();
    }
    jarFile.close();

    String fullPath = FilenameUtils.concat(outputDirectory, resourceDirectory);
    return fullPath;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top