繁体   English   中英

无法从Java程序调用批处理文件

[英]Trouble calling batch file from Java program

我读到的所有内容都表明,从Java程序中调用批处理文件的唯一方法是执行以下操作:

Process p = Runtime.getRuntime().exec("cmd /c start batch.bat");

据我了解,这将创建一个运行CMD.exe的进程,而该进程又将创建一个运行批处理文件的进程。 但是,一旦实例化了批处理文件过程,CMD.exe进程似乎将退出。

如何在CMD进程退出之前确认批处理文件已完成?

您可以尝试在cmd / c之后不使用“ start”命令来启动批处理,因为“ start.exe”为batch.bat创建了一个新进程。

Process p = Runtime.getRuntime().exec("cmd /c batch.bat");

这应该是您的正确表格。

jeb所说的话,或尝试传递/wait参数来start 这将导致start等待批处理过程完成。 首先在命令行上尝试-比重建Java应用程序快。

进程p = Runtime.getRuntime()。exec(“ cmd / c start batch.bat”);

要等待批处理文件完成(退出),请在/c之后删除“开始”。 /c告诉cmd.exe在cmd完成时返回,但是,“ start”表示启动新的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)也可以使用waitFor(long timeout, TimeUnit unit)p.isAlive()

警告如果您的批处理将向stdout和/或stderr输出大量数据(可能超过1024个字符,可能更少),则您的程序需要以某种方式处理此数据,否则,您的程序与批处理过程将填满,批处理文件将挂起,等待管道中添加新字符的空间,并且批处理文件将永远不会返回。

这是最初导致我这次进入Stack Overflow的问题。 我在批处理文件中有17,000+个命令,每个命令生成300+个字符到stdout,执行命令的任何错误都生成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 

    现在,您必须读取每个InputStream(仅当它们具有数据时,否则您将等到这样做)。 假设您从一个InputStreams中获得的数据比其他InputStreams中的数据多得多,几乎可以肯定会挂起批处理文件。 有多种方法可以读取多个流而不会挂起,但是,这超出了我已经很长的答案的范围。

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

  5. 不要忘记,如果您的批处理文件从stdin读取数据,那么您也必须进行处理。 这在Process中受支持,在ProcessBuilder中具有更多选项。

cmd /?的输出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");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM