2011-06-17 374 views
2

我有一些將文件壓縮的​​代碼通過網絡發送,然後在另一端解壓縮。我仍在測試代碼,並且源和目標都相同。壓縮文件需要一分鐘的時間。解壓縮文件需要一個小時。我認爲我的代碼中必然存在一個缺陷,以產生如此大的差異。下面的代碼來解壓縮:Java:解壓縮明顯慢於壓縮

public String uncompressLocalZip(String filename,String strUUID,ParentEntry pe,boolean bControlFileProgress) { 
     final int BUFFER = 2048; 
     BufferedOutputStream out = null; 
     ZipInputStream zis = null; 

     try { 

      FileInputStream fis = new FileInputStream(Constants.conf.getFileDirectory() + Constants.PATH_SEPARATOR + strUUID + Constants.PATH_SEPARATOR + filename); 
      zis = new ZipInputStream(new BufferedInputStream(fis)); 
      ZipEntry entry; 
      long totallength = 0; 
      long size = 0; 
      if (pe !=null) 
       size = pe.getSize(); 


      while((entry = zis.getNextEntry()) != null) { 
       System.out.println("Extracting: " +entry); 
       int count; 
       byte data[] = new byte[BUFFER]; 
       // write the files to the disk 

       File fileOutput = new File(Constants.conf.getFileDirectory() + Constants.PATH_SEPARATOR + strUUID + Constants.PATH_SEPARATOR + Constants.conf.getUncompressFolderName() + Constants.PATH_SEPARATOR + entry.getName()); 
       new File(fileOutput.getParent()).mkdirs(); 


       BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(fileOutput)); 

       out = new BufferedOutputStream(fos, BUFFER); 
       while ((count = zis.read(data, 0, BUFFER)) != -1) { 
         out.write(data, 0, count); 
         totallength += count; 

      } 
      out.flush(); 

     } 

    } 
    catch(Exception e) { 
     e.printStackTrace(); 
     return("FAILED"); 
    } 
    finally { 
     try {if (out!= null) out.close();} catch (IOException ioe) {} 
     try {if (zis!= null) zis.close();} catch (IOException ioe) {} 

    } 

    return("SUCCESS");  



} 

下面的代碼到拉鍊:

public void createLocalZip(String filename,ProcessEntry pe) { 
    ZipOutputStream out=null; 
    try { 

     File fileOutput = new File (filename); 
     out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(fileOutput))); 
     long totallength=0; 
     long size = pe.getParentEntry().getSize(); 

     String strStartDirectory; 
     if (pe.getParentEntry().isDirectory()) 
      strStartDirectory=pe.getParentEntry().getUrl(); 
     else 
      strStartDirectory=pe.getParentEntry().getFolder(); 



     for (int i=0;i<pe.getParentEntry().tableModel3.getRowCount();i++) { 
      FileEntry fe = pe.getParentEntry().tableModel3.getFileEntry(i); 
      File fileInput = new File (fe.getUrl()); 
      FileInputStream input = new FileInputStream(fileInput); 
      BufferedInputStream in = new BufferedInputStream(input); 

      String strRelativeDir = fe.getUrl().substring(strStartDirectory.length()+1,fe.getUrl().length()); 

      ZipEntry entry = new ZipEntry(strRelativeDir); 

      out.putNextEntry(entry); 


      byte[] bbuf = new byte[2048]; 
      int length=0; 




      while ((in != null) && ((length = in.read(bbuf)) != -1)) { 

        out.write(bbuf,0,length); 
        totallength += length; 
        pe.setProgress((int) (totallength*100/size)); 

      } 

      in.close(); 


     } 






    } 
    catch (Exception e) { 
     System.out.println(e.getMessage()); 
    } 
    finally { 
     try {if (out!=null) out.close();} catch(IOException ioe){} 
    } 


} 

更新:對於該特定試驗中的壓縮比爲約90%(1.2GB到大約100MB)。所以我想這可能是額外寫入磁盤解壓縮與壓縮,雖然我預計接近10倍差距與60倍。

+2

你有沒有嘗試過分析你的解壓縮代碼? – 2011-06-17 01:08:53

+0

從命令行(jar或unzip)運行它時,解壓縮同一文件需要多長時間? – Thilo 2011-06-17 01:10:36

+1

另外,請嘗試觀察內存使用情況。難道你的系統交換的太多了,因爲你的文件不適合內存,並且不知怎的,你的程序試圖把它放在那裏? – 2011-06-17 01:15:18

回答

2

不要使用BufferedOutputStream(您只需要1個BufferedOutputStream包裝器)對OutputStream進行雙重包裝,並在完成寫入後關閉它。

也,ZipEntry s可以是目錄,所以檢查並相應地處理。

+0

幾乎所有我見過的例子都建議使用緩衝輸出流(如這個http://www.javadb.com/write-to-file-using-bufferedoutputstream),否則文件I/O效率不高(我認爲每次寫入磁盤時都會有一些開銷,並且緩衝會減少開銷)。 – opike 2011-06-17 02:09:47

+0

@opike - 你正在使用_2_ BufferedOutputStreams,你只需要_1_。 – jtahlborn 2011-06-17 11:26:32

+0

緩衝兩次不應導致較慢的輸入讀數。原因必須在別處。 – 2014-03-07 19:31:40

0

我沒有真正大的文件來測試你的代碼,所以我只能猜測。

  1. 你說你的未壓縮的zip大小超過1 GB。這可能不僅僅是適合你的記憶,而且如果有東西強迫VM將內存中的所有內容都包含進來,它將不得不交換。用探查器觀察你的程序。

  2. 確保在寫入之後關閉每個FileOutputStream。 (你創建它們很多,只關閉最後一個。)

  3. 我不確定ZipInputStream的實現(可能會強制你的BufferedStream緩衝大部分數據)。您可以嘗試使用ZipFile(基本上允許隨機訪問)。