2012-09-29 121 views
0

我想解壓縮一些zip文件,它有大約65兆。下面的代碼片段:Java進程 - 無法解壓縮zip文件

這種方法實際上解壓文件:

public synchronized void execute(Path zipFile) { 
    final ProcessBuilder builder = new ProcessBuilder("/bin/unzip",zipFile.toAbsolutePath().toString(), "-d", dir.toAbsolutePath().toString()); 
    FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() { 
     @Override public Integer call() { 
      try { 
       System.out.println("started and waiting"); 
       int status = builder.start().waitFor(); 
       System.out.println("status: " + status); 
       return status; 
      } catch (InterruptedException e) { 
      } catch (IOException e) { 
      } 
      return 0; 
     } 
    }); 

    List<FutureTask<Integer>> tasks = new ArrayList<FutureTask<Integer>>(); 
    tasks.add(task); 
    System.out.println("task added"); 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    for (FutureTask<Integer> t : tasks) { 
     executor.submit(t); 
     System.out.println("submitted"); 
    } 
    executor.shutdown(); 
    System.out.println("shutdown"); 
} 

那執行人/未來的東西是存在的只是要確定我做正確。該類在Finder類中調用,該類在目錄中查找zip文件並嘗試將其解壓縮。正是基於此代碼http://docs.oracle.com/javase/tutorial/essential/io/walk.html

所以要具體:

@Override 
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 
    if (find(file)) { 
     synchronized(Finder.class) { 
      executor.execute(file); 
     } 
    } 
    return CONTINUE; 
} 

現在的問題。這真的很有趣。每當我通過這段代碼解壓縮一些東西時,zip文件實際上會解壓縮,但是隻有一些目錄解壓縮,而其他的則不是。例如,我有一個zip文件,其目錄爲temp foo和bar,但是在解壓縮之後,只有temp和foo目錄,並且不會提取它。從這個

輸出是:

task added 
submitted 
started and waiting 
shutdown 

爲什麼沒有 「狀態=東西」 輸出?

我不明白爲什麼是這樣。當我手動解壓縮它時,它會正確解壓縮。

//編輯

這並獲得成功

@Override 
public synchronized void execute(String file, String dest) { 
    ProcessBuilder pb = new ProcessBuilder("/bin/unzip","-qq", file, "-d", dest); 
    pb.redirectErrorStream(true); 

    try { 
     Process p = pb.start(); 
     InputStream is = p.getInputStream(); 
     InputStreamReader r = new InputStreamReader(is); 
     BufferedReader in = new BufferedReader(r); 
     String line; 
     while ((line = in.readLine()) != null) { 
      // because of the -qq option, it does actually write out nothing 
      System.out.println(line); 
     } 
    } catch (IOException ex) { 
     System.err.println(ex.getMessage()); 
    } 
} 
+0

'shutdown'在執行程序終止之前不會阻塞。這是'awaitTermination'。順便說一句,你可以做'Collections.singleton(任務)' – oldrinb

+0

順便說一下,共享一個執行程序......沒有意義爲每個解壓縮操作創建一個新的執行程序。 – oldrinb

+0

感謝您的提示。它沒有幫助,結果是一樣的,我加了executor.awaitTermination(1,TimeUnit.HOURS);在executor.shutdown後面,但只提取了2個dirs,根本沒有任何變化。我不得不手動殺死它:/ – stewenson

回答

2

unzip命令會將其正在解壓縮的文件的詳細信息打印到其標準輸出中,因此您需要在Java程序(通過Process.getInputStream)中閱讀此內容。如果您沒有及時讀取輸出,那麼一旦緩衝區滿了,這個過程可能會被阻塞 - 這在流程的javadoc中有詳細說明。

我建議您致電builder.redirectErrorStream(true),然後確保您讀取過程流中的所有數據。您還可以通過在解壓縮調用中添加一個參數-qq,以最大限度地減少首先創建的輸出量。

0

我認爲問題是由於超時約束。

你可以試試下面的代碼執行過程

Runtime runtime = Runtime.getRuntime(); 
Process process = runtime.exec(commandLine); 

我認爲它會工作。

+0

從功能的角度來看,Runtime api與ProcessBuilder api是否相同?例如。雖然很少進行某些處理,但我是否也可以使用您的解決方案?它有一些顯着的差異嗎? – stewenson

+0

是的兩個都提供相同的功能。唯一不同的是,運行時API獲取字符串作爲參數,並且processbuilder將字符串數組作爲參數。 – shekhar