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.
$ 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.
$ 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.
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
$ 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.
<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.
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
Thank you – very nice. This saved me tons of time (posted a small fix) below.
Nice, but what about a zip inside a zip?
I’ll need to call the method twice? ‘-‘
For embedded zip or zip inside a zip file, I’m not sure what is the general practice.
The code needs to be modified to support the embedded zip file.
if(zipEntry.getName().endsWith(".zip")){
// unzip it again...
}
I haven’t tested the above idea, but it should work; if someone has time, please test it and comment here.
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
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?
Rar and Zip are two different things./ Why would you possibly think code for one would work for the other?
Hi, Do you know how can I decompress a .rar file?
Same can be achieved out of the box using Ant Compress library
http://ant.apache.org/antlibs/compress/
Maven dependency:-
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.
Guest post will do 🙂
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:
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)
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 🙂
getResouceAsStream() is returning null, even though the zip file is present. Any idea why this happens?
I m also gettin the same error
getResourceAsStream() is returning null…
If got the solution please reply
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. 🙂
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.
AES encryption.
https://mkyong.com/java/java-aes-encryption-and-decryption/
I’m getting the next Exception
How to unzip a zip file in sftp server using java ?
It helped me a lot to know there is two kind of zip files (folder inline or separate). Thank you very much \o/
This code is insecure and vulnerable to the Zip Slip vulnerability.
https://snyk.io/research/zip-slip-vulnerability
We updated the article with zip slip validation, thanks for your feedback and zip slip article.
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).
Thanks for your feedback.
We updated the article with the latest example to unzip a file, and the above comment is irrelevant now.
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
any exception?
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?
Did you run the above unzip example? It should work and unzip your file structure correctly.
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)
We updated the unzip example with directory checking.
if (zipEntry.getName().endsWith(File.separator)) {
isDirectory = true;
}
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.
I didn’t test the performance, and the
Files.copy
is the easiest way to copy a file. May be someone can feedback on this.//— 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;
}
}
Very good tutorial. thanks a lot
Very nice tutorial..
Anyway to randomly decompress a zip file?
Random? What do you mean?
When we try to unzip huge file say 2gb. How will ZipInputStream manage the memory aspects, Please explain?
Hi, you need to change “new File(newFile.getParent()).mkdirs()” to this: new File(newFile.getParentFile()).mkdirs()
Thanks for your feedback, we updated the article with NIO
Files.createDirectories(path)
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??
java.util.zip.ZipException: invalid entry compressed size (expected 4294967295 but got 14454437 bytes)
I am getting this error.How do i solve it?
Sorry, I don’t know the answer. However, we updated the examples with latest code, try it again.
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
We updated the code, it supports sub-directories and sub-files
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.
Thanks man, you are really awesome
as always, everything works in mkyong.com
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
Sorry to hear that. We updated the code and tested with a few zip structures, it should works as expected.