开发者

Trouble calling batch file from Java program

Everything I read says that the only way to call a batch file from within a java program is to do something like this:

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

From what I understand this creates a process to run CMD.exe, which in turn creates a process to run the batch file. However, the CMD.exe process appears to exit once it has instantiated the batch file process.

How can I confirm that the batch file has compl开发者_开发知识库eted before the CMD process exits?


What jeb said, or try passing the /wait parameter to start. That should cause start to wait till the batch process completes. Try it at the command line first -- faster than rebuilding your Java app.


You could try to start the batch without the "start" command after cmd /c, as the "start.exe" creates a new process for the batch.bat.

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

This should be the correct form for you.


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

To wait for the batch file to finish (exit) you remove the "start" after the /c. The /c tells cmd.exe to return when cmd is finished, this you want, however, "start" means start a new cmd.exe process to execute the batch file. At this point the cmd.exe you started is finished and exits. Probably not what you want.

Either of the two code snippets below will get the batch file running and get you a Process object that you will need.

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

Or

ProcessBuilder pb= new ProcessBuilder ("cmd", "/c", "batch.bat");
    Process p = pb.start ();

Now that you have a Process object you have multiple ways to wait for your batch file to finish.

The simplest way is .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 ();
}

You could also use waitFor(long timeout, TimeUnit unit) or p.isAlive() if they meet your needs better.

Warning If your batch is going to output a lot of data (probably more than 1024 characters, maybe less) to stdout and / or stderr your program needs to handle this data in some manner, otherwise, the pipe (s) between your program and the batch process will fill up and the batch file will hang waiting for room in the pipe to add new characters and the batch file will never return.

This is the problem that originally brought me to Stack Overflow this time. I had 17,000+ commands in a batch file and each command generated 300+ characters to stdout and any errors executing a command generated 1000+ characters.

Some of the ways to solve this:

  1. @echo off as the 1st line in the batch file, with this the cmd process will not echo each command in the batch file. If your batch file does not generate any other output to stdout or stderr you are done.

  2. If one or more of the commands in the batch file can or may generate a lot of stdout and / or stderr output then you have to handle that data yourself.

  3. If you are using "Runtime.getRuntime().exec" you only have one way to handle this and that is to get the InputStreams for the batch file's stdout and stderr by calling:

        InputStream outIS = p.getInputStream (); // this gets the batch file's stdout
        InputStream errIS = p.getErrorStream (); // this gets the batch file's stderr
    

    Now you have to read each of the InputStreams (only when they have data or you will wait until you do). Assuming that you get a lot more data from one of the InputStreams than the other you are almost assured of hanging the batch file. There are ways to read multiple streams without hanging, however, they are beyond the scope of my already excessively long answer.

  4. If you are using ProcessBuilder pb= new ProcessBuilder ("cmd", "/c", "batch.bat"); (and this is a major reason to do so) you have a lot more options available to you since you can ask for stdout and stderr to be combined pb.redirectErrorStream (true);, easier to handle one InputStream without blocking, or you can redirect stdout and stderr to files (null files may work on Windows definitely on Unix) so you program doesn't have to handle them.

  5. Don't forget that if your batch file reads data from stdin, you have to handle that as well. This is supported in Process and with more options in ProcessBuilder.


From the output of cmd /?

/C      Carries out the command specified by string and then terminates
/K      Carries out the command specified by string but remains

Thus what you need is:

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


If you want to simply find out whether the batch file process finished or not, why not add...

echo DONE

at the end of the batch file?

Or if you program is for public use, something like...

echo finished>log.txt

would work. Then verify that it is finished from within your java program...

if (new BufferedReader(new FileReader("log.txt")).readLine().equals("finished"))
{
    System.out.println("the batch process has finished");
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜