Java IO Tutorial

How to unzip a zip file in Java

This article shows how to use ZipInputStream and zip4j library to unzip a zip file in Java.

To unzip a file manually, remember to add validation for the zip slip vulnerability.


  Path targetDirResolved = targetDir.resolve(zipEntry.getName());

  // make sure normalized file still has targetDir as its prefix
  Path normalizePath = targetDirResolved.normalize();

  if (!normalizePath.startsWith(targetDir)) {
      // may be zip slip, better stop and throws exception
      throw new IOException("Bad zip entry: " + zipEntry.getName());
  }

1. Zip File

The following zip file structure is created by this article – create zip file in Java. Later we will show how to unzip it into a new folder.

1.1 A zip file contains only files.

/home/mkyong/zip/test.zip

$ unzip -l test.zip

Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2020-08-06 18:49   test-a2.log
        0  2020-08-06 18:49   test-a1.log
       14  2020-08-06 18:49   data/db.debug.conf
       42  2020-08-06 18:49   README.md
       32  2020-08-06 18:49   Test.java
        0  2020-08-06 18:49   test-b/test-b1.txt
        0  2020-08-06 18:49   test-b/test-c/test-c2.log
        0  2020-08-06 18:49   test-b/test-c/test-c1.log
        0  2020-08-06 18:49   test-b/test-b2.txt
        0  2020-08-06 18:49   test-b/test-d/test-d2.log
        0  2020-08-06 18:49   test-b/test-d/test-d1.log
---------                     -------
       88                     11 files

1.2 A zip file contains folders and files.

/home/mkyong/zip/test.zip

$ unzip -l test.zip

Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2020-07-27 15:10   test-a2.log
        0  2020-07-23 14:55   test-a1.log
        0  2020-08-06 18:57   data/
       14  2020-08-04 14:07   data/db.debug.conf
       42  2020-08-05 19:04   README.md
       32  2020-08-05 19:04   Test.java
        0  2020-08-06 18:57   test-b/
        0  2020-07-24 15:49   test-b/test-b1.txt
        0  2020-08-06 18:57   test-b/test-c/
        0  2020-07-27 15:11   test-b/test-c/test-c2.log
        0  2020-07-27 15:11   test-b/test-c/test-c1.log
        0  2020-07-27 15:10   test-b/test-b2.txt
        0  2020-08-06 18:57   test-b/test-d/
        0  2020-07-27 15:11   test-b/test-d/test-d2.log
        0  2020-07-27 15:11   test-b/test-d/test-d1.log
---------                     -------
       88                     15 files

2. Unzip file – ZipInputStream

To unzip a zip file, we use ZipInputStream to read the zip file, and copying files from the zip file into a new folder (outside zip file).

This below example unzip a zip file /home/mkyong/zip/test.zip into a folder /home/mkyong/zip/, also provides a validation to prevent the zip slip vulnerability.

ZipFileUnZipExample.java

package com.mkyong.io.howto;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipFileUnZipExample {

    public static void main(String[] args) {

        Path source = Paths.get("/home/mkyong/zip/test.zip");
        Path target = Paths.get("/home/mkyong/zip/");

        try {

            unzipFolder(source, target);
            System.out.println("Done");

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void unzipFolder(Path source, Path target) throws IOException {

        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(source.toFile()))) {

            // list files in zip
            ZipEntry zipEntry = zis.getNextEntry();

            while (zipEntry != null) {

                boolean isDirectory = false;
                // example 1.1
                // some zip stored files and folders separately
                // e.g data/
                //     data/folder/
                //     data/folder/file.txt
                if (zipEntry.getName().endsWith(File.separator)) {
                    isDirectory = true;
                }

                Path newPath = zipSlipProtect(zipEntry, target);

                if (isDirectory) {
                    Files.createDirectories(newPath);
                } else {

                    // example 1.2
                    // some zip stored file path only, need create parent directories
                    // e.g data/folder/file.txt
                    if (newPath.getParent() != null) {
                        if (Files.notExists(newPath.getParent())) {
                            Files.createDirectories(newPath.getParent());
                        }
                    }

                    // copy files, nio
                    Files.copy(zis, newPath, StandardCopyOption.REPLACE_EXISTING);

                    // copy files, classic
                    /*try (FileOutputStream fos = new FileOutputStream(newPath.toFile())) {
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }*/
                }

                zipEntry = zis.getNextEntry();

            }
            zis.closeEntry();

        }

    }

    // protect zip slip attack
    public static Path zipSlipProtect(ZipEntry zipEntry, Path targetDir)
        throws IOException {

        // test zip slip vulnerability
        // Path targetDirResolved = targetDir.resolve("../../" + zipEntry.getName());

        Path targetDirResolved = targetDir.resolve(zipEntry.getName());

        // make sure normalized file still has targetDir as its prefix
        // else throws exception
        Path normalizePath = targetDirResolved.normalize();
        if (!normalizePath.startsWith(targetDir)) {
            throw new IOException("Bad zip entry: " + zipEntry.getName());
        }

        return normalizePath;
    }

}

Output

Terminal

$ pwd
/home/mkyong/zip/

$ tree
.
├── data
│   └── db.debug.conf
├── README.md
├── test-a1.log
├── test-a2.log
├── test-b
│   ├── test-b1.txt
│   ├── test-b2.txt
│   ├── test-c
│   │   ├── test-c1.log
│   │   └── test-c2.log
│   └── test-d
│       ├── test-d1.log
│       └── test-d2.log
├── Test.java

3. Unzip file – zip4j

This example uses the zip4j library to unzip a zip file.

pom.xml

  <dependency>
      <groupId>net.lingala.zip4j</groupId>
      <artifactId>zip4j</artifactId>
      <version>2.6.1</version>
  </dependency>

  // it takes `File` as arguments
  public static void unzipFolderZip4j(Path source, Path target)
        throws IOException {

        new ZipFile(source.toFile())
                .extractAll(target.toString());

  }

4. ZipException: invalid entry size

If we hit the following invalid entry size exception, it means the zip file is corrupted during the copy, transfer, or creation process. There is no way to fix a corrupted file size, get a new zip file again.

Terminal

java.util.zip.ZipException: invalid entry size (expected 0 but got 1282 bytes)
	at java.base/java.util.zip.ZipInputStream.readEnd(ZipInputStream.java:398)
	at java.base/java.util.zip.ZipInputStream.read(ZipInputStream.java:197)
	at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107)
	at com.mkyong.io.howto.ZipFileUnZipExample.unzipFolder(ZipFileUnZipExample.java:63)
	at com.mkyong.io.howto.ZipFileUnZipExample.main(ZipFileUnZipExample.java:22)

Download Source Code

$ git clone https://github.com/mkyong/core-java

$ cd java-io/howto

References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
59 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Joseph Francis
6 years ago

Thank you – very nice. This saved me tons of time (posted a small fix) below.

Rhuan
6 years ago

Nice, but what about a zip inside a zip?
I’ll need to call the method twice? ‘-‘

Nur
9 years ago

Hey man, you are awsome. actually this programm saves my time a lot and i change it a bit so that it can go to a directory and fild all zip files and unzip them. thanks again

Rohit
10 years ago

I tried this code , It works perfectly with .zip files only. but not with .rar. It returns null. If I want extract data from .rar file so what to do?

ClintJCL
10 years ago
Reply to  Rohit

Rar and Zip are two different things./ Why would you possibly think code for one would work for the other?

Nayyereh Fazileh
9 years ago
Reply to  ClintJCL

Hi, Do you know how can I decompress a .rar file?

Sambhav
11 years ago

Same can be achieved out of the box using Ant Compress library

http://ant.apache.org/antlibs/compress/

Maven dependency:-

<dependency>
	<groupId>org.apache.ant</groupId>
	<artifactId>ant-compress</artifactId>
	<version>1.2</version>
</dependency>
Unzip unzipper = new Unzip();
unzipper.setSrc(theZIPFile);
unzipper.setDest(theTargetFolder);
unzipper.execute();
Ashwin
11 years ago

Your site is simply wonderful. Small snippets so useful to use/understand as part of a bigger code. Appreciate it and do let me know if there is anyway I can contribute it to the site in anyway.

Aleksandar Fotev
11 years ago

Not sure if this is the right place to post this but maybe it will help somebody.
Mine problem was that i had a zip inside of my runnable jar file that needed to be extracted . The zip had folders inside.
how to get the zip file from inside the jar:

InputStream stream;
stream = this.getClass().getClassLoader().getSystemResourceAsStream("resources/Sounds.zip");

where the resources is the folder/package inside of the root of the jar
now is the rest of the code (a little modification of the original one)


package system;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
 
public class UnZip
{
    List<String> fileList;
 
    UnZip(InputStream stream, File dest)
    {
    	unZipIt(stream,dest); // the stream i got from the first part and dest as a file
    }
 
    /**
     * Unzip it
     * @param stream input zip file
     * @param output zip file output folder
     */
    public void unZipIt(InputStream stream, File dest){
 
     byte[] buffer = new byte[1024];
 
     try{
 
    	//create output directory is not exists
    	File folder = dest;
    	if(!folder.exists()){
    		folder.mkdir();
    	}
 
    	//get the zip file content
    	ZipInputStream zis = 
    		new ZipInputStream(stream);
    	//get the zipped file list entry
    	ZipEntry ze = zis.getNextEntry();
 
    	while(ze!=null){
 
    	   String fileName = ze.getName();
           File newFile = new File(dest + File.separator + fileName);
 
           System.out.println("file unzip : "+ newFile.getAbsoluteFile());
 
            //create all non exists folders
            //else you will hit FileNotFoundException for compressed folder
 
           if(ze.isDirectory()) 
           {
        	   new File(newFile.getParent()).mkdirs();
           }
           else
           {
        	FileOutputStream fos = null;
 
            new File(newFile.getParent()).mkdirs();
 
            fos = new FileOutputStream(newFile);             
 
            int len;
            while ((len = zis.read(buffer)) > 0) 
            {
       		fos.write(buffer, 0, len);
            }
 
            fos.close();   
           }
 
           ze = zis.getNextEntry();
    	}
 
        zis.closeEntry();
    	zis.close();
 
    	System.out.println("Done");
 
    }catch(IOException ex){
       ex.printStackTrace(); 
    }
   }    
}

with this i was able to extract files and folders from the zip to a desired location.
Hope it can prevent some headToWall love <3 🙂

m13g7
10 years ago

getResouceAsStream() is returning null, even though the zip file is present. Any idea why this happens?

Chitra
10 years ago
Reply to  m13g7

I m also gettin the same error
getResourceAsStream() is returning null…
If got the solution please reply

Felix
11 years ago

Thanks a lot! I was happy that someone posted a solution to the same problem as I had. There should be more people like you. 🙂

Manojkumar
11 years ago

Hi every one,

I am having one password protected file, which is created using
PKZIP utility (http://www.pkware.com/software/pkzip)

My question how do i encrypt zip file if i don’t know which encryption Algorithm,
it’s using. I have the password.

let me know if any one is having any idea.

Héctor Yaque
8 months ago

I’m getting the next Exception

java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
Arjun
1 year ago

How to unzip a zip file in sftp server using java ?

Raphaël
2 years ago

It helped me a lot to know there is two kind of zip files (folder inline or separate). Thank you very much \o/

Florent Guillaume
4 years ago

This code is insecure and vulnerable to the Zip Slip vulnerability.
https://snyk.io/research/zip-slip-vulnerability

Ji?í Horák
5 years ago

The sourcecode is wrong. No offense, just pointing out the mistake. On win8 when there’s folder inside zip file, the code looks for parent dir and do not asks if the current “file” is a dir, therefore the dir is created as “file” with 0 size and without any file suffix, and then the attempt to create now the parent folder – with the same name as the 0 size file – will fail and first attempt to actually unzip file into that folder throws an exception. Before calling the FileOutputStream, make sure the file is not a folder (dot in filename for example).

Ashok
5 years ago

How to unzip folder having file names with special characters for e.g. test.zip having file with name fndStaticLookups_finder=LookupTypeFinder%3BBindLookupType%3DACTIVITY_SHOWTIMEAS_CD.json

David Gong
5 years ago

Hi mkyong
I have a zip file which contains multiple CSV files and some folders. These folders also contains CSV files.
In a word, I wonder how to deal with this kind of zip file recursively?

veera
5 years ago

private static final String INPUT_ZIP_FILE = “/classes/sds.zip”;
private static final String OUTPUT_FOLDER = “/classes/testdata/

Exception :::

java.io.FileNotFoundException: sds.zip (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at com.test.zip.UnZip.unZipIt(UnZip.java:43)
at com.test.zip.UnZip.main(UnZip.java:19)

Thanks
6 years ago

FileOutputStream fos = new FileOutputStream(newFile);

int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}

fos.close();

Wouldn’t a BufferedWriter probably be faster ? Just a thought. Thanks for the tuto.

Joseph Francis
6 years ago

//— Here is a fix so that is creates when there are sub-directories .. this creates if needed
// Note: If you had run it before, remove the existing files because there may be a blank file holding the spot of the directory

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.FilenameUtils;

public class FileUnzipper {
List fileList;

/*
* private static final String INPUT_ZIP_FILE = “C:\MyFile.zip”; private
* static final String OUTPUT_FOLDER = “C:\outputzip”;
*
* public static void main( String[] args ) { FileUnzipper unZip = new
* FileUnzipper(); unZip.unZipIt(INPUT_ZIP_FILE,OUTPUT_FOLDER); }
*
*/
/**
* Unzip it
*
* @param zipFile
* input zip file
* @param output
* zip file output folder
*/
public static boolean unZipIt(String zipFile, String outputFolder) {
boolean tmpRet = true;
byte[] buffer = new byte[1024];

try {

// create output directory is not exists
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdir();
}

// get the zip file content
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
// get the zipped file list entry
ZipEntry ze = zis.getNextEntry();

while (ze != null) {

String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);

String tmpCheckFN = FilenameUtils.removeExtension(fileName);

if (tmpCheckFN.equalsIgnoreCase(fileName)) {
// — Directory, create if needed
if (!newFile.exists()) {
System.out.println(“Create dir ” + outputFolder + File.separator + fileName);
boolean success = newFile.mkdirs();
if (!success) {
System.err.println(“Could not create directory for ” + fileName + “.”);
return false;
}
}
} else {
System.out.println(“file unzip : ” + newFile.getAbsoluteFile());

new File(newFile.getParent()).mkdirs();

FileOutputStream fos = new FileOutputStream(newFile);

int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}

fos.close();
}

ze = zis.getNextEntry();
}

zis.closeEntry();
zis.close();

System.out.println(“Done”);

} catch (IOException ex) {
tmpRet = false;
ex.printStackTrace();
}

return tmpRet;
}
}

Safoora
6 years ago

Very good tutorial. thanks a lot

Safoora
6 years ago

Very nice tutorial..

Andrew Sheron
7 years ago

Anyway to randomly decompress a zip file?

Goutham Nithyananda
8 years ago

When we try to unzip huge file say 2gb. How will ZipInputStream manage the memory aspects, Please explain?

Paul Muntyanu
8 years ago

Hi, you need to change “new File(newFile.getParent()).mkdirs()” to this: new File(newFile.getParentFile()).mkdirs()

Bharath B S
8 years ago

Hi,

When i run the code with the ZIP file of mediumsize but when my ZIP file is in the size of GB’s the code fails with File Not Found Exception.

Can anyone help me to resolve my issue??

vin
9 years ago

java.util.zip.ZipException: invalid entry compressed size (expected 4294967295 but got 14454437 bytes)

I am getting this error.How do i solve it?

Ph?m Nguy?n Hà Trung
9 years ago

Somehow I can’t make your code to work.
– If a folder in the zip file has a . in its name, it is read as a file and stuck there
– If we have a folder inside a folder, there will be errors in various cases
– Your code only works if there’s only 1 folder containing all the files

David Mendoza
9 years ago

Mkyong, your advice has been helpful in learning java. I do have a question, how can I read a zip file that contains other zip files? I need to process all files within a zip file that contains other zip files. I want to process (read) all log files. My issues is that my loop doesn’t know how to deal with an embedded zip file. I’l using java zipfile routines.

Vishal Dasa
9 years ago

Thanks man, you are really awesome

yair
9 years ago

as always, everything works in mkyong.com

Nuno Brito
9 years ago

This code was problematic. Used a whole morning to get a working code for zip files with multiple folders inside. Ended up using ZT-Zip as alternative. Easy, two lines of code.

Get the Jar and code sample to extract files their GitHub page: https://github.com/zeroturnaround/zt-zip