繁体   English   中英

Java的解压缩实用程序性能不佳

[英]Poor Performance of Java's unzip utilities

我注意到与使用WinZip等本机工具相比,Java中的解压缩工具非常慢。

是否有可用于Java的第三方库更高效? 开源是首选。

编辑

这是使用Java内置解决方案vs 7zip的速度比较。 我在原始解决方案中添加了缓冲输入/输出流(感谢Jim,这确实产生了很大的不同)。

Zip文件大小:800K Java解决方案:2.7秒7Zip解决方案:204毫秒

以下是使用内置Java解压缩的修改代码:

/** Unpacks the give zip file using the built in Java facilities for unzip. */
@SuppressWarnings("unchecked")
public final static void unpack(File zipFile, File rootDir) throws IOException
{
  ZipFile zip = new ZipFile(zipFile);
  Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zip.entries();
  while(entries.hasMoreElements()) {
    ZipEntry entry = entries.nextElement();
    java.io.File f = new java.io.File(rootDir, entry.getName());
    if (entry.isDirectory()) { // if its a directory, create it
      continue;
    }

    if (!f.exists()) {
      f.getParentFile().mkdirs();
      f.createNewFile();
    }

    BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry)); // get the input stream
    BufferedOutputStream bos = new BufferedOutputStream(new java.io.FileOutputStream(f));
    while (bis.available() > 0) {  // write contents of 'is' to 'fos'
      bos.write(bis.read());
    }
    bos.close();
    bis.close();
  }
}

问题不在于解压缩,而是将解压缩的数据写回磁盘的效率低下。 我的基准测试显示使用

    InputStream is = zip.getInputStream(entry); // get the input stream
    OutputStream os = new java.io.FileOutputStream(f);
    byte[] buf = new byte[4096];
    int r;
    while ((r = is.read(buf)) != -1) {
      os.write(buf, 0, r);
    }
    os.close();
    is.close();

相反,将方法的执行时间减少了5倍(对于6 MB的zip文件,从5秒减少到1秒)。

可能的罪魁祸首是你使用bis.available() 除了不正确(可用返回读取调用之前的字节数将阻塞,直到流的末尾),这将绕过BufferedInputStream提供的缓冲,需要对复制到输出文件中的每个字节进行本机系统调用。

注意在BufferedStream该包装是没有必要的,如果你使用批量读取和写入方法,如我上面做的,该代码以关闭资源也不例外安全(如读取或写入由于某种原因失败,既不is也不os会被关闭)。 最后,如果你在类路径中有IOUtils,我建议使用经过良好测试的IOUtils.copy而不是自己滚动。

确保在Java应用程序中为解压缩方法提供BufferedInputStream。 如果你犯了使用无缓冲输入流的错误,那么你的IO性能肯定会很糟糕。

我发现了一个“不优雅”的解决方案。 有一个免费使用的开源实用程序7zip(www.7-zip.org)。 您可以下载命令行版本( http://www.7-zip.org/download.html )。 7-zip仅在Windows上受支持,但看起来已经移植到其他平台(p7zip)。

显然,这种解决方案并不理想,因为它是特定于平台的,并且依赖于可执行文件。 但是,与在Java中进行解压缩相比,速度令人难以置信。

以下是我为与此实用程序进行交互而创建的实用程序函数的代码。 由于下面的代码是Windows特定的,因此还有改进的余地。

/** Unpacks the zipfile to the output directory.  Note: this code relies on 7-zip 
   (specifically the cmd line version, 7za.exe).  The exeDir specifies the location of the 7za.exe utility. */
public static void unpack(File zipFile, File outputDir, File exeDir) throws IOException, InterruptedException
{
  if (!zipFile.exists()) throw new FileNotFoundException(zipFile.getAbsolutePath());
  if (!exeDir.exists()) throw new FileNotFoundException(exeDir.getAbsolutePath());
  if (!outputDir.exists()) outputDir.mkdirs();

  String cmd = exeDir.getAbsolutePath() + "/7za.exe -y e " + zipFile.getAbsolutePath();

  ProcessBuilder builder = new ProcessBuilder(new String[] { "cmd.exe", "/C", cmd });
  builder.directory(outputDir);
  Process p = builder.start();
  int rc = p.waitFor();
  if (rc != 0) {
    log.severe("Util::unpack() 7za process did not complete normally.  rc: " + rc);
  }
}      

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM