【问题标题】:Trouble calling batch file from Java program从 Java 程序调用批处理文件时遇到问题
【发布时间】:2011-09-20 19:03:44
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你现在应该使用ProcessBuilder 而不是Runtime.getRuntime().exe()

标签: java file batch-file command


【解决方案1】:

jeb 说了什么,或者尝试将/wait 参数传递给start。这应该会导致start 等待批处理完成。首先在命令行中尝试——比重新构建 Java 应用程序更快。

【讨论】:

  • 我同意你的观点,start /wait 应该可以工作,但是使用/wait 开关将完全不需要启动。
  • 我想是这样,但也许 OP 需要它在一个单独的窗口中?注意:我不是批处理文件专家。 :)
  • 似乎离开“开始”会导致程序挂起。我不知道为什么。
  • 这是最好的解决方案,尽管它只在保留“start”时才有效。
【解决方案2】:

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

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

这应该是适合您的正确格式。

【讨论】:

  • 对但是你想确认cmd完成你需要添加p.waitFor();
  • 或者如果你不想阻塞你的线程,你可以尝试读取 p.exitValue()
  • 如果我排除启动,整个程序挂起。
  • 当您启动 cmd /c 时,它不会显示控制台。如果进程正在运行,请与任务管理器联系。如果你想显示控制台试试cmd /c start /wait cmd /c batch.bat。我成功运行了这个测试Process p = Runtime.getRuntime().exec("cmd /c start /wait cmd /c \"c:\\batch.bat > %temp%\\out\""); p.waitFor();
【解决方案3】:

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

要等待批处理文件完成(退出),请删除/c 之后的“开始”。 /c 告诉 cmd.exe 在 cmd 完成后返回,这是你想要的,但是,“start”意味着启动一个新的 cmd.exe 进程来执行批处理文件。至此你启动的 cmd.exe 完成并退出。可能不是你想要的。

下面的两个代码 sn-ps 中的任何一个都将使批处理文件运行并为您提供所需的 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 的问题。我在一个批处理文件中有 17,000 多个命令,每个命令生成 300 多个字符到标准输出,执行命令的任何错误都会生成 1000 多个字符。

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

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

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

  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 获得的数据比另一个多得多,您几乎可以肯定会挂起批处理文件。有一些方法可以在不挂起的情况下读取多个流,但是,它们超出了我已经过长的答案的范围。

  4. 1234563处理一个 InputStream 而不阻塞,或者您可以将 stdout 和 stderr 重定向到文件(空文件可能在 Windows 上肯定在 Unix 上工作),因此您的程序不必处理它们。
  5. 不要忘记,如果您的批处理文件从标准输入读取数据,您也必须处理它。这在 Process 中受支持,并且在 ProcessBuilder 中提供更多选项。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 但是 cmd.exe 永远不会结束。而且batch.bat完全在另一个进程中运行(因为它是由start.exe启动的)
    • 那是错误的。 “启动启动单独的命令提示符窗口以运行指定的程序或命令。不带参数使用时,启动会打开第二个命令提示符窗口。”。在这种情况下,您不应使用“开始”。
    • 排除“开始”会导致我的程序挂起。这是为什么呢?
    • 可能批处理永远不会完成?当您从命令行运行批处理文件并使用您传递给exec() 的相同参数/标志时会发生什么?
    • 批处理文件单独运行正常,所以我不太确定
    【解决方案5】:

    如果你想简单地了解批处理文件处理是否完成,为什么不添加......

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

    【讨论】:

    • 嗯,这个想法是检查批处理文件是否完成,以便我可以在 cmd.exe 进程终止之前运行另一个命令。
    • 另外,批处理文件的内容是用户定义的。本质上,我正在制作一个批处理文件编辑器(具有一些特殊功能)。
    猜你喜欢
    • 2016-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 2011-03-06
    相关资源
    最近更新 更多