2010-03-15 121 views
2

這是一個後續問題,以我的其他問題:Run bat file in Java and wait運行bat文件,並等待2

我張貼此作爲一個單獨的問題的原因是一個我已經問了正確回答。從一些研究中我發現我的問題對我而言是獨一無二的,所以我決定創建一個新的問題。在繼續這個問題之前,請仔細閱讀這個問題,因爲它們密切相關。

運行建議的代碼會阻止waitFor調用中的程序。經過一番研究,我發現waitFor方法會阻止如果你的進程有輸出需要被處理,所以你應該先清空輸出流和錯誤流。我做了這些事情,但我的方法仍然阻止。然後我發現了一個建議,只需等待exitValue方法返回進程的退出值並處理拋出的異常,並暫停一段時間以避免消耗所有CPU,就可以簡單地循環。我這樣做:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

public class Test { 

public static void main(String[] args) { 
    try { 
    Process p = Runtime.getRuntime().exec(
    "cmd /k start SQLScriptsToRun.bat" + " -UuserName -Ppassword" 
     + " projectName"); 
    final BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    final BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream())); 
    new Thread(new Runnable() { 

    @Override 
    public void run() { 
    try { 
     while (input.readLine()!=null) {} 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 
    }).start(); 
    new Thread(new Runnable() { 

    @Override 
    public void run() { 
    try { 
     while (error.readLine()!=null) {} 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 
    }).start(); 
    int i = 0; 
    boolean finished = false; 
    while (!finished) { 
    try { 
    i = p.exitValue(); 
    finished = true; 
    } catch (IllegalThreadStateException e) { 
    e.printStackTrace(); 
    try { 
     Thread.sleep(500); 
    } catch (InterruptedException e1) { 
     e1.printStackTrace(); 
    } 
    } 
    } 
    System.out.println(i); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 
} 
} 

但我的過程不會結束!我一直得到這個錯誤:

java.lang.IllegalThreadStateException: process has not exited 

任何想法,爲什麼我的過程不會退出?還是你有任何庫建議處理正確執行批處理文件,並等待直到執行完成?

回答

3

開始cmd/c開關代替/k和擺脫start

Process p = Runtime.getRuntime().exec( 
    "cmd /c SQLScriptsToRun.bat" + " -UuserName -Ppassword" 
    + " projectName"); 

/k告訴cmd:「運行該命令,然後繼續開放」,而/c說:「那個命令運行後退出「。

/k用於交互式使用,您希望初始化批處理文件,之後仍然使用控制檯。

但是,您的主要問題在於您正在通過使用start創建另一個過程。要運行批處理文件,這是完全不必要的,並且可以防止您知道批處理完全運行的時間,因爲Java引用了您開始的原始cmd進程,而不是您用start生成的進程。

原則上,這現在看起來如下:

  1. Java程序啓動
  2. Java程序運行cmd,並指示其運行start foo.bat堅持包容開放,交互式輸入(/k
  3. 的Java存儲進程ID(PID 42)以稍後參考該進程

    • cmd(PID 42)開始
    • cmd(PID 42)運行start foo.bat
    • start foo.bat推出的cmd另一個實例,因爲這是應該發生運行批處理文件什麼
      • cmd(PID 57005)開始
      • cmd (PID 57005)運行foo.bat
      • cmd(PID 57005)退出(這標誌着您想了解的事件)
    • cmd(PID 42)顯示提示並乖乖地等待輸入(不知道的是他們的提示是永遠不會被用戶看到,並沒有輸入都不會來了......但cmd(PID 42)等待.. 。)
  4. 的Java喜歡瞭解過程是否完成,並檢查PID 42

  5. 是的,它仍然存在。怎麼辦?

你想要什麼(什麼上述變化會做)是:

  1. Java程序啓動
  2. Java程序運行cmd,並指示其上運行的命令後,運行foo.bat和關閉(/c
  3. Java存儲進程ID(PID 42)以稍後參考該進程

    • cmd(PID 42)開始
    • cmd(PID 42)運行foo.bat
    • cmd(PID 42)離開
  4. 爪哇喜歡知道該過程是否完成,並檢查PID 42

  5. Hooray,進程已經結束,批處理文件已經運行。
+0

這將導致進程立即退出。我想要的是等到它完成。 – 2010-03-15 15:51:06

+0

@sav:刪除'start'。 – Joey 2010-03-15 15:53:17

+0

是的,我想到了,但不幸的是,如果你自己嘗試一下,你會發現它不會執行bat文件...我嘗試了所有的組合。沒有用。有些將永遠阻止,有些將不會彈出cmd窗口... – 2010-03-15 16:12:10