How to Unzip a ZIP File in Java

In this tutorial, we will learn how to unzip a ZIP file using Java’s built-in java.util.zip package, while also discussing the Zip Slip vulnerability and how to avoid it.

Table of Contents:

1. Extracting a ZIP File in Java

We can use the ZipInputStream class from java.util.zip to extract files from a ZIP archive. Here’s a step-by-step example:

UnzipUtility.java

package com.mkyong.unzip;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class UnzipUtility {

    public static void unzip(String zipFilePath, String destDirectory) 
            throws IOException {

        Path destDirPath = Paths.get(destDirectory);
        if (!Files.exists(destDirPath)) {
            Files.createDirectories(destDirPath);
        }

        try (ZipInputStream zipIn = new ZipInputStream(
                Files.newInputStream(Paths.get(zipFilePath)))) {
            ZipEntry entry = zipIn.getNextEntry();

            while (entry != null) {
                Path outPath = destDirPath.resolve(entry.getName()).normalize();

                // Prevent Zip Slip vulnerability
                if (!outPath.startsWith(destDirPath)) {
                    throw new IOException("Entry is outside of target dir: " 
                            + entry.getName());
                }

                if (entry.isDirectory()) {
                    Files.createDirectories(outPath);
                } else {
                    extractFile(zipIn, outPath);
                }
                zipIn.closeEntry();
                entry = zipIn.getNextEntry();
            }
        }
    }

    private static void extractFile(ZipInputStream zipIn, Path outPath) 
            throws IOException {

        // Ensure parent directories exist before creating the file
        // Create all necessary parent directories before writing the file.
        // Prevents NoSuchFileException for nested folders like /folder1/folder2/file.txt
        Files.createDirectories(outPath.getParent());

        try (BufferedOutputStream bos = new BufferedOutputStream(
                Files.newOutputStream(outPath))) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = zipIn.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
        }
    }

    public static void main(String[] args) {
        String zipFilePath = "files.zip";
        String destDir = "outputDir";
        try {
            unzip(zipFilePath, destDir);
            System.out.println("Unzip successful!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. Understanding the Zip Slip Vulnerability

What is Zip Slip?

Zip Slip is a path traversal vulnerability that allows an attacker to overwrite files outside the intended extraction directory. It happens when malicious ZIP archives contain filenames like:


../../../../etc/passwd

Without validation, this can overwrite critical system files.

How to Prevent Zip Slip?

To mitigate this risk, we must:

  • Use Path#normalize() to resolve and sanitize paths.
  • Ensure extracted paths stay within the intended directory using startsWith().

Secure Validation Code

We can add the following check in our code to prevent Zip Slip:


    Path outPath = destDirPath.resolve(entry.getName()).normalize();
    
    if (!outPath.startsWith(destDirPath)) {
        throw new IOException("Entry is outside of target dir: " + entry.getName());
    }

This ensures extracted files remain inside the target directory, preventing path traversal attacks.

Legacy java.io.* Validation Code

For the legacy java.io.*, we can add the following check in our code to prevent Zip Slip:


    String canonicalDestination = destDir.getCanonicalPath();
    String canonicalOutFile = outFile.getCanonicalPath();
    
    if (!canonicalOutFile.startsWith(canonicalDestination)) {
        throw new IOException("Entry is outside of target dir: " + entry.getName());
    }

3. References

mkyong

Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities.

59 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Joseph Francis
8 years ago

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

Rhuan
8 years ago

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

Nur
11 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
12 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
12 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
11 years ago
Reply to  ClintJCL

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

Sambhav
13 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
13 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
13 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
13 years ago

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

Chitra
12 years ago
Reply to  m13g7

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

Felix
13 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
13 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
2 years ago

I’m getting the next Exception

java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
Arjun
3 years ago

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

Raphaël
5 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
6 years ago

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

Ji?í Horák
7 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
7 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
7 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
8 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
8 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
8 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
9 years ago

Very good tutorial. thanks a lot

Safoora
9 years ago

Very nice tutorial..

Andrew Sheron
9 years ago

Anyway to randomly decompress a zip file?

Goutham Nithyananda
10 years ago

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

Paul Muntyanu
10 years ago

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

Bharath B S
10 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
11 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
11 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
11 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
11 years ago

Thanks man, you are really awesome

yair
11 years ago

as always, everything works in mkyong.com

Nuno Brito
11 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