How to unzip files programmatically in Android?

JavaAndroidUnzip

Java Problem Overview


I need a small code snippet which unzips a few files from a given .zip file and gives the separate files according to the format they were in the zipped file. Please post your knowledge and help me out.

Java Solutions


Solution 1 - Java

Had peno's version optimised a bit. The increase in performance is perceptible.

private boolean unpackZip(String path, String zipname)
{       
     InputStream is;
     ZipInputStream zis;
     try 
     {
         String filename;
         is = new FileInputStream(path + zipname);
         zis = new ZipInputStream(new BufferedInputStream(is));          
         ZipEntry ze;
         byte[] buffer = new byte[1024];
         int count;

         while ((ze = zis.getNextEntry()) != null) 
         {
             filename = ze.getName();
             
             // Need to create directories if not exists, or
             // it will generate an Exception...
             if (ze.isDirectory()) {
                File fmd = new File(path + filename);
                fmd.mkdirs();
                continue;
             }
            
             FileOutputStream fout = new FileOutputStream(path + filename);

             while ((count = zis.read(buffer)) != -1) 
             {
                 fout.write(buffer, 0, count);             
             }

             fout.close();               
             zis.closeEntry();
         }

         zis.close();
     } 
     catch(IOException e)
     {
         e.printStackTrace();
         return false;
     }

    return true;
}

Solution 2 - Java

Based on Vasily Sochinsky's answer a bit tweaked & with a small fix:

public static void unzip(File zipFile, File targetDirectory) throws IOException {
    ZipInputStream zis = new ZipInputStream(
            new BufferedInputStream(new FileInputStream(zipFile)));
    try {
        ZipEntry ze;
        int count;
        byte[] buffer = new byte[8192];
        while ((ze = zis.getNextEntry()) != null) {
            File file = new File(targetDirectory, ze.getName());
            File dir = ze.isDirectory() ? file : file.getParentFile();
            if (!dir.isDirectory() && !dir.mkdirs())
                throw new FileNotFoundException("Failed to ensure directory: " +
                        dir.getAbsolutePath());
            if (ze.isDirectory())
                continue;
            FileOutputStream fout = new FileOutputStream(file);
            try {
                while ((count = zis.read(buffer)) != -1)
                    fout.write(buffer, 0, count);
            } finally {
                fout.close();
            }
            /* if time should be restored as well
            long time = ze.getTime();
            if (time > 0)
                file.setLastModified(time);
            */
        }
    } finally {
        zis.close();
    }
}

Notable differences

  • public static - this is a static utility method that can be anywhere.
  • 2 File parameters because String are :/ for files and one could not specify where the zip file is to be extracted before. Also path + filename concatenation > https://stackoverflow.com/a/412495/995891
  • throws - because catch late - add a try catch if really not interested in them.
  • actually makes sure that the required directories exist in all cases. Not every zip contains all the required directory entries in advance of file entries. This had 2 potential bugs:
  • if the zip contains an empty directory and instead of the resulting directory there is an existing file, this was ignored. The return value of mkdirs() is important.
  • could crash on zip files that don't contain directories.
  • increased write buffer size, this should improve performance a bit. Storage is usually in 4k blocks and writing in smaller chunks is usually slower than necessary.
  • uses the magic of finally to prevent resource leaks.

So

unzip(new File("/sdcard/pictures.zip"), new File("/sdcard"));

should do the equivalent of the original

unpackZip("/sdcard/", "pictures.zip")

Solution 3 - Java

This is my unzip method, which I use:

private boolean unpackZip(String path, String zipname)
{		
	 InputStream is;
	 ZipInputStream zis;
	 try 
	 {
		 is = new FileInputStream(path + zipname);
		 zis = new ZipInputStream(new BufferedInputStream(is));			 
	     ZipEntry ze;
	     
	     while((ze = zis.getNextEntry()) != null) 
	     {
	         ByteArrayOutputStream baos = new ByteArrayOutputStream();
	         byte[] buffer = new byte[1024];
	         int count;
	         
	         String filename = ze.getName();
	         FileOutputStream fout = new FileOutputStream(path + filename);
	         
	         // reading and writing
	         while((count = zis.read(buffer)) != -1) 
	         {
	             baos.write(buffer, 0, count);
	             byte[] bytes = baos.toByteArray();
	             fout.write(bytes);             
	             baos.reset();
	         }

	         fout.close();		         
	         zis.closeEntry();
	     }
	     
	     zis.close();
	 } 
	 catch(IOException e)
	 {
		 e.printStackTrace();
		 return false;
	 }

	return true;
}

Solution 4 - Java

The Kotlin way

//FileExt.kt

data class ZipIO (val entry: ZipEntry, val output: File)

fun File.unzip(unzipLocationRoot: File? = null) {
    
    val rootFolder = unzipLocationRoot ?: File(parentFile.absolutePath + File.separator + nameWithoutExtension)
    if (!rootFolder.exists()) {
       rootFolder.mkdirs()
    }

    ZipFile(this).use { zip ->
        zip
        .entries()
        .asSequence()
        .map {
            val outputFile = File(rootFolder.absolutePath + File.separator + it.name)
            ZipIO(it, outputFile)
        }
        .map {
            it.output.parentFile?.run{
                if (!exists()) mkdirs()
            }
            it
        }
        .filter { !it.entry.isDirectory }
        .forEach { (entry, output) ->
            zip.getInputStream(entry).use { input ->
                output.outputStream().use { output ->
                    input.copyTo(output)
                }
            }
        }
    }

}

Usage

val zipFile = File("path_to_your_zip_file")
file.unzip()

Solution 5 - Java

Android has build-in Java API. Check out java.util.zip package.

The class ZipInputStream is what you should look into. Read ZipEntry from the ZipInputStream and dump it into filesystem/folder. Check similar example to compress into zip file.

Solution 6 - Java

While the answers that are already here work well, I found that they were slightly slower than I had hoped for. Instead I used zip4j, which I think is the best solution because of its speed. It also allowed for different options for the amount of compression, which I found useful.

Solution 7 - Java

use the following class

	import java.io.BufferedOutputStream;
	import java.io.File;
	import java.io.FileInputStream;
	import java.io.FileOutputStream;
	import java.util.zip.ZipEntry;
	import java.util.zip.ZipInputStream;
	import android.util.Log;

	public class DecompressFast {



 private String _zipFile; 
  private String _location; 
 
  public DecompressFast(String zipFile, String location) { 
    _zipFile = zipFile; 
    _location = location; 
 
    _dirChecker(""); 
  } 
 
  public void unzip() { 
    try  { 
      FileInputStream fin = new FileInputStream(_zipFile); 
      ZipInputStream zin = new ZipInputStream(fin); 
      ZipEntry ze = null; 
      while ((ze = zin.getNextEntry()) != null) { 
        Log.v("Decompress", "Unzipping " + ze.getName()); 
 
        if(ze.isDirectory()) { 
          _dirChecker(ze.getName()); 
        } else { 
          FileOutputStream fout = new FileOutputStream(_location + ze.getName()); 
         BufferedOutputStream bufout = new BufferedOutputStream(fout);
          byte[] buffer = new byte[1024];
          int read = 0;
          while ((read = zin.read(buffer)) != -1) {
              bufout.write(buffer, 0, read);
          }

          
          
          
          bufout.close();
          
          zin.closeEntry(); 
          fout.close(); 
        } 
         
      } 
      zin.close(); 
      
      
      Log.d("Unzip", "Unzipping complete. path :  " +_location );
    } catch(Exception e) { 
      Log.e("Decompress", "unzip", e); 
      
      Log.d("Unzip", "Unzipping failed");
    } 
 
  } 
 
  private void _dirChecker(String dir) { 
    File f = new File(_location + dir); 
 
    if(!f.isDirectory()) { 
      f.mkdirs(); 
    } 
  } 


 }

How to use

 String zipFile = Environment.getExternalStorageDirectory() + "/the_raven.zip"; //your zip file location
    String unzipLocation = Environment.getExternalStorageDirectory() + "/unzippedtestNew/"; // destination folder location
  DecompressFast df= new DecompressFast(zipFile, unzipLocation);
    df.unzip();

Permissions

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Solution 8 - Java

According to @zapl answer,Unzip with progress report:

public interface UnzipFile_Progress
{
	void Progress(int percent, String FileName);
}

// unzip(new File("/sdcard/pictures.zip"), new File("/sdcard"));
public static void UnzipFile(File zipFile, File targetDirectory, UnzipFile_Progress progress) throws IOException,
		FileNotFoundException
{
	long total_len = zipFile.length();
	long total_installed_len = 0;
	
	ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
	try
	{
		ZipEntry ze;
		int count;
		byte[] buffer = new byte[1024];
		while ((ze = zis.getNextEntry()) != null)
		{
			if (progress != null)
			{
				total_installed_len += ze.getCompressedSize();
				String file_name = ze.getName();
				int percent = (int)(total_installed_len * 100 / total_len);
				progress.Progress(percent, file_name);
			}
			
			File file = new File(targetDirectory, ze.getName());
			File dir = ze.isDirectory() ? file : file.getParentFile();
			if (!dir.isDirectory() && !dir.mkdirs())
				throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath());
			if (ze.isDirectory())
				continue;
			FileOutputStream fout = new FileOutputStream(file);
			try
			{
				while ((count = zis.read(buffer)) != -1)
					fout.write(buffer, 0, count);
			} finally
			{
				fout.close();
			}

			// if time should be restored as well
			long time = ze.getTime();
			if (time > 0)
				file.setLastModified(time);
		}
	} finally
	{
		zis.close();
	}
}

Solution 9 - Java

public class MainActivity extends Activity {

private String LOG_TAG = MainActivity.class.getSimpleName();

private File zipFile;
private File destination;

private TextView status;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    status = (TextView) findViewById(R.id.main_status);
    status.setGravity(Gravity.CENTER);
    
    if ( initialize() ) {
    	zipFile = new File(destination, "BlueBoxnew.zip");
    	try {
			Unzipper.unzip(zipFile, destination);
			status.setText("Extracted to \n"+destination.getAbsolutePath());
		} catch (ZipException e) {
			Log.e(LOG_TAG, e.getMessage());
		} catch (IOException e) {
			Log.e(LOG_TAG, e.getMessage());
		}
    } else {
    	status.setText("Unable to initialize sd card.");
    }
}

public boolean initialize() {
	boolean result = false;
	 File sdCard = new File(Environment.getExternalStorageDirectory()+"/zip/");
	//File sdCard = Environment.getExternalStorageDirectory();
	if ( sdCard != null ) {
		destination = sdCard;
		if ( !destination.exists() ) {
			if ( destination.mkdir() ) {
				result = true;
			}
		} else {
			result = true;
		}
	}
	
	return result;
}

 }

->Helper Class(Unzipper.java)

    import java.io.File;
    import java.io.FileInputStream;
   import java.io.FileOutputStream;
    import java.io.IOException;
       import java.util.zip.ZipEntry;
    import java.util.zip.ZipException;
    import java.util.zip.ZipInputStream;
     import android.util.Log;

   public class Unzipper {

private static String LOG_TAG = Unzipper.class.getSimpleName();

public static void unzip(final File file, final File destination) throws ZipException, IOException {
	new Thread() {
		public void run() {
			long START_TIME = System.currentTimeMillis();
			long FINISH_TIME = 0;
			long ELAPSED_TIME = 0;
			try {
				ZipInputStream zin = new ZipInputStream(new FileInputStream(file));
				String workingDir = destination.getAbsolutePath()+"/";

				byte buffer[] = new byte[4096];
				int bytesRead;
				ZipEntry entry = null;
				while ((entry = zin.getNextEntry()) != null) {
					if (entry.isDirectory()) {
						File dir = new File(workingDir, entry.getName());
						if (!dir.exists()) {
							dir.mkdir();
						}
						Log.i(LOG_TAG, "[DIR] "+entry.getName());
					} else {
						FileOutputStream fos = new FileOutputStream(workingDir + entry.getName());
						while ((bytesRead = zin.read(buffer)) != -1) {
							fos.write(buffer, 0, bytesRead);
						}
						fos.close();
						Log.i(LOG_TAG, "[FILE] "+entry.getName());
					}
				}
				zin.close();
				
				FINISH_TIME = System.currentTimeMillis();
				ELAPSED_TIME = FINISH_TIME - START_TIME;
				Log.i(LOG_TAG, "COMPLETED in "+(ELAPSED_TIME/1000)+" seconds.");
			} catch (Exception e) {
				Log.e(LOG_TAG, "FAILED");
			}
		};
	}.start();
}

   }

->xml layout(activity_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".MainActivity" >

<TextView
    android:id="@+id/main_status"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text="@string/hello_world" />

</RelativeLayout>

->permission in Menifest file:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Solution 10 - Java

Here is a ZipFileIterator (like a java Iterator, but for zip files):

package ch.epfl.bbp.io;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipFileIterator implements Iterator<File> {

    private byte[] buffer = new byte[1024];

    private FileInputStream is;
    private ZipInputStream zis;
    private ZipEntry ze;

    public ZipFileIterator(File file) throws FileNotFoundException {
	is = new FileInputStream(file);
	zis = new ZipInputStream(new BufferedInputStream(is));
    }

    @Override
    public boolean hasNext() {
	try {
	    return (ze = zis.getNextEntry()) != null;
	} catch (IOException e) {
	    e.printStackTrace();
	}
	return false;
    }

    @Override
    public File next() {
	try {
	    ByteArrayOutputStream baos = new ByteArrayOutputStream();
	    int count;

	    String filename = ze.getName();
	    File tmpFile = File.createTempFile(filename, "tmp");
	    tmpFile.deleteOnExit();// TODO make it configurable
	    FileOutputStream fout = new FileOutputStream(tmpFile);

	    while ((count = zis.read(buffer)) != -1) {
		baos.write(buffer, 0, count);
		byte[] bytes = baos.toByteArray();
		fout.write(bytes);
		baos.reset();
	    }
	    fout.close();
	    zis.closeEntry();

	    return tmpFile;

	} catch (Exception e) {
	    throw new RuntimeException(e);
	}
    }

    @Override
    public void remove() {
	throw new RuntimeException("not implemented");
    }

    public void close() {
	try {
	    zis.close();
	    is.close();
	} catch (IOException e) {// nope
	}
    }
}

Solution 11 - Java

Minimal example I used to unzip a specific file from my zipfile into my applications cache folder. I then read the manifest file using a different method.

private void unzipUpdateToCache() {
    ZipInputStream zipIs = new ZipInputStream(context.getResources().openRawResource(R.raw.update));
    ZipEntry ze = null;

    try {

        while ((ze = zipIs.getNextEntry()) != null) {
            if (ze.getName().equals("update/manifest.json")) {
                FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/manifest.json");

                byte[] buffer = new byte[1024];
                int length = 0;

                while ((length = zipIs.read(buffer))>0) {
                    fout.write(buffer, 0, length);
                }
                zipIs .closeEntry();
                fout.close();
            }
        }
        zipIs .close();

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

}

Solution 12 - Java

I'm working with zip files which Java's ZipFile class isn't able to handle. Java 8 apparently can't handle compression method 12 (bzip2 I believe). After trying a number of methods including zip4j (which also fails with these particular files due to another issue), I had success with Apache's commons-compress which supports additional compression methods as mentioned here.

Note that the ZipFile class below is not the one from java.util.zip.

It's actually org.apache.commons.compress.archivers.zip.ZipFile so be careful with the imports.

try (ZipFile zipFile = new ZipFile(archiveFile)) {
    Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
    while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();
        File entryDestination = new File(destination, entry.getName());
        if (entry.isDirectory()) {
            entryDestination.mkdirs();
        } else {
            entryDestination.getParentFile().mkdirs();
            try (InputStream in = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream(entryDestination)) {
                IOUtils.copy(in, out);
            }
        }
    }
} catch (IOException ex) {
    log.debug("Error unzipping archive file: " + archiveFile, ex);
}

For Gradle:

compile 'org.apache.commons:commons-compress:1.18'

Solution 13 - Java

Based on zapl's answer, adding try() around Closeable's closes the streams automatically after use.

public static void unzip(File zipFile, File targetDirectory) {
    try (FileInputStream fis = new FileInputStream(zipFile)) {
        try (BufferedInputStream bis = new BufferedInputStream(fis)) {
            try (ZipInputStream zis = new ZipInputStream(bis)) {
                ZipEntry ze;
                int count;
                byte[] buffer = new byte[Constant.DefaultBufferSize];
                while ((ze = zis.getNextEntry()) != null) {
                    File file = new File(targetDirectory, ze.getName());
                    File dir = ze.isDirectory() ? file : file.getParentFile();
                    if (!dir.isDirectory() && !dir.mkdirs())
                        throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath());
                    if (ze.isDirectory())
                        continue;
                    try (FileOutputStream fout = new FileOutputStream(file)) {
                        while ((count = zis.read(buffer)) != -1)
                            fout.write(buffer, 0, count);
                    }
                }
            }
        }
    } catch (Exception ex) {
        //handle exception
    }
}

Using Constant.DefaultBufferSize (65536) gotten from C# .NET 4 Stream.CopyTo from Jon Skeet's answer here: https://stackoverflow.com/a/411605/1876355

I always just see posts using byte[1024] or byte[4096] buffer, never knew it can be much larger which improves performance and is still working perfectly normal.

Here is the Stream Source code: https://referencesource.microsoft.com/#mscorlib/system/io/stream.cs

> //We pick a value that is the largest multiple of 4096 that is still smaller than the large object heap threshold (85K). > // The CopyTo/CopyToAsync buffer is short-lived and is likely to be collected at Gen0, and it offers a significant > // improvement in Copy performance. > > private const int _DefaultCopyBufferSize = 81920;

However, I dialed it back to 65536 which is also a multiple of 4096 just to be safe.

Solution 14 - Java

Password Protected Zip File

if you want to compress files with password you can take a look at this library that can zip files with password easily:

Zip:

ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);

Unzip:

ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);

Rar:

RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);

The documentation of this library is good enough, I just added a few examples from there. It's totally free and wrote specially for android.

Solution 15 - Java

Here is more concise version of @arsent solution:

fun File.unzip(to: File? = null) {
    val destinationDir = to ?: File(parentFile, nameWithoutExtension)
    destinationDir.mkdirs()

    ZipFile(this).use { zipFile ->
        zipFile
            .entries()
            .asSequence()
            .filter { !it.isDirectory }
            .forEach { zipEntry ->
                val currFile = File(destinationDir, zipEntry.name)
                currFile.parentFile?.mkdirs()
                zipFile.getInputStream(zipEntry).use { input ->
                    currFile.outputStream().use { output -> input.copyTo(output) }
                }
            }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKartikView Question on Stackoverflow
Solution 1 - JavaVasily SochinskyView Answer on Stackoverflow
Solution 2 - JavazaplView Answer on Stackoverflow
Solution 3 - JavapetrnohejlView Answer on Stackoverflow
Solution 4 - JavaarsentView Answer on Stackoverflow
Solution 5 - JavaankitjaininfoView Answer on Stackoverflow
Solution 6 - JavajcwView Answer on Stackoverflow
Solution 7 - JavaManoharView Answer on Stackoverflow
Solution 8 - JavaBehrouz.MView Answer on Stackoverflow
Solution 9 - JavauserDroidView Answer on Stackoverflow
Solution 10 - JavaRenaudView Answer on Stackoverflow
Solution 11 - JavanilsiView Answer on Stackoverflow
Solution 12 - JavaManiusView Answer on Stackoverflow
Solution 13 - JavaPierreView Answer on Stackoverflow
Solution 14 - JavaMilad FaridniaView Answer on Stackoverflow
Solution 15 - Javaa.ch.View Answer on Stackoverflow