【问题标题】:How to speed up unzipping time in Java / Android?如何加快 Java / Android 中的解压缩时间?
【发布时间】:2011-05-29 02:31:32
【问题描述】:

在 android 上解压缩文件似乎非常慢。起初我以为这只是模拟器,但在手机上似乎是一样的。我尝试了不同的压缩级别,最终下降到存储模式,但仍然需要很长时间。

总之,一定是有原因的!还有其他人有这个问题吗?我的解压方法是这样的:

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

}
    }

【问题讨论】:

  • 考虑解压的位置。 Context.getCacheDir() 将是内部存储,其中 Environment.getDataDirectory() 可能是内部的(或不是),而 Environment.getExternalDirectory() 将在 SD 卡上。内存几乎肯定会更快。

标签: java android android-emulator unzip zipinputstream


【解决方案1】:

我不知道在 Android 上解压缩是否很慢,但在循环中逐字节复制肯定会更慢。尝试使用 BufferedInputStream 和 BufferedOutputStream - 它可能会更复杂一些,但根据我的经验,这最终是值得的。

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

然后你可以这样写:

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

【讨论】:

  • 为什么不把BufferedInputStream放在FileInputStream和ZipInputStream之间呢?即FileInputStream fin = new FileInputStream(zipFile); BufferedInputStream bin = new BufferedInputStream(fin); ZipInputStream zin = new ZipInputStream(bin);
  • 如果读取和写入是在像样本循环这样的数组上执行的,那么用缓冲流包装流的好处就会减少。当消费者/生产者无法使用字节数组并逐字节执行操作时,缓冲流可提高性能。
  • 太棒了。从每件解压缩 5 秒的项目大约 5 分钟开始。救生员...谢谢罗伯特
  • 我的时间从 40 分钟缩短到 3 秒。 o_O
  • 解压 8101 png 文件从 19 分钟开始
【解决方案2】:

感谢罗伯特的解决方案。 我修改了我的解压缩方法,现在只需要几秒钟而不是 2 分钟。 也许有人对我的解决方案感兴趣。所以给你:

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

【讨论】:

  • 嗨,handleDirectory 是什么?
  • 对不起,我忽略了它。在解压后的文件是文件夹的情况下,创建新文件夹是一种简单的方法。我在上面加了
  • 抱歉回复晚了。缓冲区的大小是随机选择的。缓冲区由 ZipInputStream 填充并由 FileOutputStream 清空,直到所有字节都传输完毕。所以缓冲区的大小只影响缓冲区被填充和清空的次数。小型或大型缓冲区可能各有利弊。但说实话,我并没有花那么多心思在这上面。
  • 这非常快:)
  • 太棒了。非常感谢。工作就像魅力,速度就像火箭。!
【解决方案3】:

使用上述想法和其他一些来源的想法我创建了这个类

创建这个新类

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

用法

只需将 zip 文件的文件位置和目标位置传递给此类
例子

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

不要忘记在清单中添加以下权限(如果版本高于 marshmellow,则还有运行时权限)

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

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

希望对你有帮助

【讨论】:

  • 它就像一个魅力!谢啦!你救了我一辈子!
【解决方案4】:

可以找到帮助我学习如何压缩和解压缩的 URL here

我将该 URL 与上面 user3203118 的答案结合使用来解压缩。这是供遇到此问题并需要帮助解决此问题的人将来参考。

下面是我正在使用的 ZipManager 代码:

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

【讨论】:

  • 如果可能的话,如果您可以在答案中包含代码,我认为同样有此问题的用户会非常高兴;-)
  • 我已经添加了我目前正在使用的 zip 管理器,并且像冠军一样工作
  • 我从您的代码中得到一个错误,因为在特殊情况下,文件条目出现在文件夹条目之前。因此,文件写入失败。我在声明fout变量之前引入了一个新函数:File f = new File(this.destinationFolder + filePath); File parentDir = f.getParentFile(); if (parentDir!=null) { if (parentDir.isDirectory() == false) parentDir.mkdirs(); }
【解决方案5】:

只要调用这个方法,它会给你更好的性能..

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

【讨论】:

    【解决方案6】:

    如果使用 BufferedOutputStream,请务必刷新它。如果不这样做,小于缓冲区的大小将无法正确解压缩

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

    【讨论】:

    • 非常感谢。我赞成你的回答。解压缩后我的音频文件被剪短了。忘了像你说的那样调用 out.flush()
    猜你喜欢
    • 1970-01-01
    • 2011-10-30
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    相关资源
    最近更新 更多