簡體   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