¿Cómo descomprimir archivos programáticamente en Android?

Necesito un pequeño fragmento de código que descomprime unos pocos archivos de un archivo .zip dado y proporciona los archivos separados de acuerdo con el formato en el que estaban en el archivo comprimido. Por favor, publique su conocimiento y ayúdenme.

Tenía la versión de Peno optimizada un poco. El aumento en el rendimiento es 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) { // zapis do souboru 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); // cteni zipu a zapis 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; } 

Basado en la respuesta de Vasily Sochinsky un poco ajustado y con una pequeña solución:

 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 restred as well long time = ze.getTime(); if (time > 0) file.setLastModified(time); */ } } finally { zis.close(); } } 

Diferencias notables

  • public static : este es un método de utilidad estático que puede estar en cualquier lugar.
  • 2 File parámetros del File porque String son: / para archivos y no se pudo especificar dónde se extraerá antes el archivo zip. También concatenación de path + filename > https://stackoverflow.com/a/412495/995891
  • throws – porque atrasa tarde – agregue una captura de prueba si realmente no le interesan.
  • en realidad se asegura de que existan los directorios requeridos en todos los casos. No todos los archivos comprimidos contienen todas las entradas de directorio requeridas antes de las entradas de archivos. Esto tuvo 2 errores potenciales:
    • si el archivo comprimido contiene un directorio vacío y en lugar del directorio resultante hay un archivo existente, esto fue ignorado. El valor de retorno de mkdirs() es importante.
    • podría bloquearse en archivos zip que no contienen directorios.
  • mayor tamaño de buffer de escritura, esto debería mejorar el rendimiento un poco. Por lo general, el almacenamiento se realiza en bloques de 4k y escribir en trozos más pequeños suele ser más lento de lo necesario.
  • utiliza la magia de finally para evitar fugas de recursos.

Asi que

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

debería hacer el equivalente del original

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

Este es mi método de descompresión, que uso:

 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; } 

Android tiene una API Java incorporada. Consulte el paquete java.util.zip .

La clase ZipInputStream es lo que debes considerar. Lea ZipEntry de ZipInputStream y voltéelo en el sistema de archivos / carpeta. Verifique un ejemplo similar para comprimir en un archivo zip .

Si bien las respuestas que ya están aquí funcionan bien, descubrí que eran un poco más lentas de lo que esperaba. En su lugar usé zip4j , que creo que es la mejor solución debido a su velocidad. También permitió diferentes opciones para la cantidad de compresión, que encontré útil.

De acuerdo con @zapl respuesta, descomprimir con informe de progreso:

 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 restred as well long time = ze.getTime(); if (time > 0) file.setLastModified(time); } } finally { zis.close(); } } 

ACTUALIZACIÓN 2016 use la siguiente clase

  package com.example.zip; 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(); } } } 

Cómo utilizar

  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(); 

Permisos

    
 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; } } 

-> Clase de ayuda (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(); } } 

-> diseño xml (activity_main.xml):

    

-> permiso en el archivo Menifest:

  

La manera de Kotlin

 //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) } } } } } 

Uso

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

Aquí hay un ZipFileIterator (como un iterador de Java, pero para archivos zip):

 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 { 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 } } } 

Ejemplo mínimo que solía descomprimir un archivo específico de mi archivo zip en mi carpeta de caché de aplicaciones. Luego leo el archivo de manifiesto usando un método diferente.

 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(); } } 

Archivo Zip protegido con contraseña

Si desea comprimir archivos con contraseña, puede echar un vistazo a esta biblioteca que puede comprimir archivos con contraseña fácilmente:

Cremallera:

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

Abrir la cremallera:

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

Rar:

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

La documentación de esta biblioteca es lo suficientemente buena, acabo de agregar algunos ejemplos de allí. Es totalmente gratis y escribió especialmente para Android.

Estoy trabajando con archivos zip que la clase ZipFile de Java no puede manejar. Java 8 aparentemente no puede manejar el método de compresión 12 (creo que bzip2). Después de probar varios métodos, incluido zip4j (que también falla con estos archivos en particular debido a otro problema), tuve éxito con Compresss-compress de Apache, que admite métodos de compresión adicionales como se menciona aquí .

Tenga en cuenta que la clase ZipFile a continuación no es la de java.util.zip.

En realidad es org.apache.commons.compress.archivers.zip.ZipFile así que ten cuidado con las importaciones.

 try (ZipFile zipFile = new ZipFile(archiveFile)) { Enumeration 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); } 

Para Gradle:

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