我读到的所有内容都表明,从java程序中调用批处理文件的唯一方法是执行以下操作:
Process p = Runtime.getRuntime().exec("cmd /c start batch.bat");
据我所知,这将创建一个运行CMD.exe的进程,而CMD.exe又会创建一个用于运行批处理文件的进程。但是,一旦CMD.exe进程实例化了批处理文件进程,它就会退出。
如何在CMD进程退出之前确认批处理文件已完成
jeb说了什么,或者尝试将/wait
参数传递给start
。这将导致start
等待,直到批处理过程完成。先在命令行中尝试一下——比重新构建Java应用程序更快。
您可以尝试在cmd/c之后不使用"start"命令启动批处理,因为"start.exe"为batch.bat创建了一个新进程。
Process p = Runtime.getRuntime().exec("cmd /c batch.bat");
这对你来说应该是正确的表格。
进程p=Runtime.getRuntime().exec("cmd/c start batch.bat");
要等待批处理文件完成(退出),请删除/c
之后的"开始"。当cmd完成时,/c
命令会告诉cmd.exe返回,但是,"启动"意味着启动一个新的cmd.exe进程来执行批处理文件。此时,您启动的cmd.exe已完成并退出。可能不是你想要的。
下面的两个代码片段中的任何一个都将运行批处理文件,并为您提供所需的Process对象
Process p = Runtime.getRuntime().exec("cmd /c batch.bat");
或
ProcessBuilder pb= new ProcessBuilder ("cmd", "/c", "batch.bat");
Process p = pb.start ();
现在您有了一个Process对象,就有多种方法可以等待批处理文件完成。
最简单的方法是.waitFor()
int batchExitCode = -1;
try {
batchExitCode = p.waitFor ();
} catch (InterruptedException e) {
// kill batch and re-throw the interrupt
p.destroy (); // could also use p.destroyForcibly ()
Thread.currentThread ().interrupt ();
}
如果waitFor(long timeout, TimeUnit unit)
或p.isAlive()
能更好地满足您的需求,您也可以使用它们。
警告如果您的批处理将向stdout和/或stderr输出大量数据(可能超过1024个字符,也可能更少),则您的程序需要以某种方式处理这些数据,否则,程序和批处理进程之间的管道将填满,批处理文件将挂起,等待管道中的空间添加新字符,批处理文档将永远不会返回。
这就是最初让我想到Stack Overflow的问题。我在一个批处理文件中有17000多个命令,每个命令向stdout生成300多个字符,执行命令时的任何错误都会生成1000多个字符。
解决这个问题的一些方法:
@echo off
作为批处理文件中的第一行,因此cmd进程不会回显批处理文件的每个命令。如果您的批处理文件没有向stdout或stderr生成任何其他输出,那么您就完了。如果批处理文件中的一个或多个命令可以或可能生成大量stdout和/或stderr输出,那么您必须自己处理这些数据。
如果您使用的是"Runtime.getRuntime().exec",则只有一种方法可以处理此问题,即通过调用:获取批处理文件的stdout和stderr的InputStreams
InputStream outIS = p.getInputStream (); // this gets the batch file's stdout InputStream errIS = p.getErrorStream (); // this gets the batch file's stderr
现在,您必须读取每个InputStreams(仅当它们有数据时,否则您将等待数据)。假设您从其中一个InputStreams获得的数据比另一个多得多,那么您几乎可以放心挂起批处理文件。有一些方法可以在不挂起的情况下阅读多个流,然而,它们超出了我已经过长的答案的范围。
如果您正在使用
ProcessBuilder pb= new ProcessBuilder ("cmd", "/c", "batch.bat");
(这是这样做的一个主要原因),您有更多的选项可供选择,因为您可以要求将stdout和stderr组合为pb.redirectErrorStream (true);
,更容易处理一个InputStream而不阻塞,或者您可以将stdout或stderr重定向到文件(空文件在Windows上肯定可以在Unix上工作),这样您的程序就不必处理它们。不要忘记,如果您的批处理文件从stdin读取数据,您也必须处理它。Process和Processor中的更多选项都支持此功能。
来自cmd /?
的输出
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
因此,您需要的是:
Process p = Runtime.getRuntime().exec("cmd /k start batch.bat");
如果您想简单地了解批处理文件过程是否完成,为什么不添加。。。
echo DONE
在批处理文件的末尾?
或者,如果你的程序是供公众使用的,比如。。。
echo finished>log.txt
会起作用。然后从您的java程序中验证它是否已完成。。。
if (new BufferedReader(new FileReader("log.txt")).readLine().equals("finished"))
{
System.out.println("the batch process has finished");
}