从Java程序调用批处理文件时出现问题



我读到的所有内容都表明,从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多个字符。

解决这个问题的一些方法:

  1. @echo off作为批处理文件中的第一行,因此cmd进程不会回显批处理文件的每个命令。如果您的批处理文件没有向stdout或stderr生成任何其他输出,那么您就完了。

  2. 如果批处理文件中的一个或多个命令可以或可能生成大量stdout和/或stderr输出,那么您必须自己处理这些数据。

  3. 如果您使用的是"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获得的数据比另一个多得多,那么您几乎可以放心挂起批处理文件。有一些方法可以在不挂起的情况下阅读多个流,然而,它们超出了我已经过长的答案的范围。

  4. 如果您正在使用ProcessBuilder pb= new ProcessBuilder ("cmd", "/c", "batch.bat");(这是这样做的一个主要原因),您有更多的选项可供选择,因为您可以要求将stdout和stderr组合为pb.redirectErrorStream (true);,更容易处理一个InputStream而不阻塞,或者您可以将stdout或stderr重定向到文件(空文件在Windows上肯定可以在Unix上工作),这样您的程序就不必处理它们。

  5. 不要忘记,如果您的批处理文件从stdin读取数据,您也必须处理它。ProcessProcessor中的更多选项都支持此功能。

来自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");
}

相关内容

  • 没有找到相关文章

最新更新