2010-12-21 10 views
29

Descomprimir archivos en Android parece ser terriblemente lento. Al principio pensé que esto era solo el emulador pero parece ser el mismo en el teléfono. Probé con diferentes niveles de compresión y eventualmente bajé al modo de almacenamiento, pero aún demora años.¿Cómo acelerar el tiempo de descompresión en Java/Android?

De todos modos, debe haber una razón! ¿Alguien más tiene este problema? Mi método de descompresión se ve así:

public void unzip() 
{ 
try{ 
     FileInputStream fin = new FileInputStream(zipFile); 
     ZipInputStream zin = new ZipInputStream(fin); 
     File rootfolder = new File(directory); 
     rootfolder.mkdirs(); 
     ZipEntry ze = null; 
     while ((ze = zin.getNextEntry())!=null){ 

      if(ze.isDirectory()){ 
       dirChecker(ze.getName()); 
      } 
      else{ 
       FileOutputStream fout = new FileOutputStream(directory+ze.getName()); 

      for(int c = zin.read();c!=-1;c=zin.read()){ 
       fout.write(c); 
      } 
       //Debug.out("Closing streams"); 
       zin.closeEntry(); 
       fout.close(); 

     } 
    } 
    zin.close(); 
} 
catch(Exception e){ 
      //Debug.out("Error trying to unzip file " + zipFile); 

} 
    } 
+1

considere dónde está descomprimiendo. Contexto.getCacheDir() va a ser un almacenamiento interno, donde Environment.getDataDirectory() puede ser interno (o no) y Environment.getExternalDirectory() estará en la tarjeta SD. la memoria interna es casi seguro que va a ser más rápida. –

Respuesta

63

No sé si descomprimir en Android es lento, pero la copia byte a byte en un bucle es sin duda frenarla aún más. Intenta usar BufferedInputStream y BufferedOutputStream, puede ser un poco más complicado, pero en mi experiencia, al final vale la pena.

BufferedInputStream in = new BufferedInputStream(zin); 
BufferedOutputStream out = new BufferedOutputStream(fout); 

Y entonces se puede escribir con algo así:

byte b[] = new byte[1024]; 
int n; 
while ((n = in.read(b,0,1024)) >= 0) { 
    out.write(b,0,n); 
} 
+3

¿Por qué no poner BufferedInputStream entre FileInputStream y ZipInputStream? Es decir, 'FileInputStream fin = new FileInputStream (zipFile); BufferedInputStream bin = new BufferedInputStream (fin); ZipInputStream zin = new ZipInputStream (bin); ' –

+0

impresionante - Le daré una oportunidad – digitalWestie

+1

Si las lecturas y escrituras se realizan en arreglos como el bucle de muestra, se reduce el beneficio de envolver las secuencias con flujos de búfer. Las secuencias de almacenamiento en búfer proporcionan mejoras de rendimiento cuando el consumidor/productor es incapaz de trabajar con matrices de bytes y realiza operaciones byte por byte. –

18

Gracias por la solución de Robert. Modifiqué mi método de unizip y ahora solo toma unos pocos segundos en vez de 2 minutos. Quizás alguien esté interesado en mi solución. Así que aquí van:

public void unzip() { 

    try { 
     FileInputStream inputStream = new FileInputStream(filePath); 
     ZipInputStream zipStream = new ZipInputStream(inputStream); 
     ZipEntry zEntry = null; 
     while ((zEntry = zipStream.getNextEntry()) != null) { 
      Log.d("Unzip", "Unzipping " + zEntry.getName() + " at " 
        + destination); 

      if (zEntry.isDirectory()) { 
       hanldeDirectory(zEntry.getName()); 
      } else { 
       FileOutputStream fout = new FileOutputStream(
         this.destination + "/" + zEntry.getName()); 
       BufferedOutputStream bufout = new BufferedOutputStream(fout); 
       byte[] buffer = new byte[1024]; 
       int read = 0; 
       while ((read = zipStream.read(buffer)) != -1) { 
        bufout.write(buffer, 0, read); 
       } 

       zipStream.closeEntry(); 
       bufout.close(); 
       fout.close(); 
      } 
     } 
     zipStream.close(); 
     Log.d("Unzip", "Unzipping complete. path : " + destination); 
    } catch (Exception e) { 
     Log.d("Unzip", "Unzipping failed"); 
     e.printStackTrace(); 
    } 

} 

public void hanldeDirectory(String dir) { 
     File f = new File(this.destination + dir); 
     if (!f.isDirectory()) { 
      f.mkdirs(); 
     } 
} 
+0

Hola, ¿qué es handleDirectory? – Caipivara

+1

Oh lo siento, lo pasé por alto. Es un método simple para crear una nueva carpeta en el caso de que el archivo que se descomprimió sea una carpeta. Lo agregué sobre – thoxxer

+0

¿Cómo se sabe la longitud de la matriz de bytes? (1024) – ThanosFisherman

4

La dirección URL que me ayudó a aprender cómo comprimir y descomprimir se puede encontrar here.

Utilicé esa URL en conjunto con la respuesta anterior del usuario3203118 para descomprimir. Esto es para futuras referencias de personas que se topan con este tema y necesitan ayuda para resolverlo.

A continuación se muestra el código ZipManager estoy usando:

public class ZipManager { 

    private static final int BUFFER = 80000; 

    public void zip(String[] _files, String zipFileName) { 
     try { 
      BufferedInputStream origin = null; 
      FileOutputStream dest = new FileOutputStream(zipFileName); 
      ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
       dest)); 
      byte data[] = new byte[BUFFER]; 

      for (int i = 0; i < _files.length; i++) { 
       Log.v("Compress", "Adding: " + _files[i]); 
       FileInputStream fi = new FileInputStream(_files[i]); 
       origin = new BufferedInputStream(fi, BUFFER); 

       ZipEntry entry = new ZipEntry(_files[i].substring(_files[i] 
        .lastIndexOf("/") + 1)); 
       out.putNextEntry(entry); 
       int count; 

       while ((count = origin.read(data, 0, BUFFER)) != -1) { 
        out.write(data, 0, count); 
       } 
       origin.close(); 
      } 
      out.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public void unzip(String _zipFile, String _targetLocation) { 


     // create target location folder if not exist 
     dirChecker(_targetLocation); 

     try { 
      FileInputStream fin = new FileInputStream(_zipFile); 
      ZipInputStream zin = new ZipInputStream(fin); 
      ZipEntry ze = null; 
      while ((ze = zin.getNextEntry()) != null) { 

       // create dir if required while unzipping 
       if (ze.isDirectory()) { 
        dirChecker(ze.getName()); 
       } else { 
        FileOutputStream fout = new FileOutputStream(
        _targetLocation + "/" + 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); 
        } 

        zin.closeEntry(); 
        bufout.close(); 
        fout.close(); 
       } 
      } 
      zin.close(); 
     } catch (Exception e) { 
      System.out.println(e); 
     } 
    } 

    private void dirChecker(String dir) { 
     File f = new File(dir); 
     if (!f.isDirectory()) { 
      f.mkdirs(); 
     } 
    } 
} 
+0

Creo que los usuarios que también tengan este problema estarían muy contentos si pudieran incluir el código en su respuesta, si es posible ;-) –

+0

He agregado mi administrador de archivos zip que actualmente estoy usando y funciona como un champ – hafridi

+0

Recibí un error de su código porque en una situación peculiar, la entrada del archivo venía antes de la entrada de la carpeta. Por lo tanto, la escritura del archivo estaba fallando. He introducido una nueva función antes de declarar la variable '' fout'': '' File f = new File (this.destinationFolder + filePath); Archivo parentDir = f.getParentFile(); if (parentDir! = Null) { if (parentDir.isDirectory() == false) parentDir.mkdirs(); } '' – seoul

3

Sólo llaman a este método y se le dará un rendimiento mucho mejor ..

public boolean unzip(Context context) { 
    try { 
     FileInputStream fin = new FileInputStream(_zipFile); 
     ZipInputStream zin = new ZipInputStream(fin); 
     BufferedInputStream in = new BufferedInputStream(zin); 
     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 out = new BufferedOutputStream(fout); 
        byte b[] = new byte[1024]; 
       for (int c = in.read(b,0,1024); c != -1; c = in.read()) { 
        out.write(b,0,c); 
       } 
       zin.closeEntry(); 
       fout.close(); 
      } 
     } 
     zin.close(); 
     return true; 
    } catch (Exception e) { 
     Log.e("Decompress", "unzip", e); 
     return false; 
    } 
} 

    private void _dirChecker(String dir) { 
    File f = new File(_location + dir); 
    if (!f.isDirectory()) { 
     f.mkdirs(); 
    } 
} 
0

En caso de utilizar BufferedOutputStream asegúrese de enjuagar eso. Si no lo hace, el tamaño más pequeño que la memoria intermedia no ser descomprimido correctamente

if (ze.isDirectory()) { 
       _dirChecker(ze.getName()); 
      } else { 
       FileOutputStream fout = new FileOutputStream(_location 
         + ze.getName()); 
        BufferedOutputStream out = new BufferedOutputStream(fout); 
        byte buffer[] = new byte[1024]; 
       for (int c = in.read(buffer,0,1024); c != -1; c = in.read()) { 
        out.write(buffer,0,c); 
       } 
       out.flush();//flush it...... 
       zin.closeEntry(); 
       fout.close(); 
      } 
7

Actualización 2016

usando ideas anteriores y las ideas de algunas otras fuentes he creado esta clase

crear este nuevo clase

package com.example.Unzipdemo; 

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

USO

sólo tiene que pasar el archivo de l sitio donde se encuentra de archivo zip y su destino Localización de esta clase
ejemplo

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

No se olvide de añadir siguientes permisos en el manifiesto (el permiso de tiempo también se ejecutan si la versión más alta que marshmellow)

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

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

esperanza esto ayuda