2010-03-15 116 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