Проблемы с вызовом командного файла из Java-программы - PullRequest
2 голосов
/ 23 июня 2011

Все, что я прочитал, говорит, что единственный способ вызвать командный файл из Java-программы - это сделать что-то вроде этого:

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

Из того, что я понимаю, создается процесс для запуска CMD.exe, который, в свою очередь, создает процесс для запуска пакетного файла.Однако процесс CMD.exe завершается, как только он создает экземпляр процесса пакетного файла.

Как я могу подтвердить, что пакетный файл завершен до завершения процесса CMD?

Ответы [ 5 ]

2 голосов
/ 23 июня 2011

Вы можете попробовать запустить пакет без команды "start" после cmd / c, так как "start.exe" создает новый процесс для batch.bat.

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

Это должно бытьправильная форма для вас.

2 голосов
/ 23 июня 2011

Что сказал Джеб, или попробуйте передать параметр /wait в start. Это должно заставить start ждать завершения пакетного процесса. Сначала попробуйте в командной строке - быстрее, чем перестраивать ваше Java-приложение.

1 голос
/ 18 марта 2016

Процесс p = Runtime.getRuntime (). Exec ("cmd / c start batch.bat");

Чтобы дождаться завершения пакетного файла (выхода), который вы удаляете«начало» после /c./c указывает cmd.exe возвращаться после завершения cmd, однако это нужно, однако «запуск» означает запуск нового процесса 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(), если они лучше соответствуют вашим потребностям.

Предупреждение Если ваша партия будет выводитьсябольшая часть данных (вероятно, более 1024 символов, может быть меньше) для stdout и / или stderr вашей программе должна каким-то образом обрабатывать эти данные, в противном случае канал (ы) между вашей программой и пакетным процессом заполнятся, ипакетный файл будет зависать в ожидании места в трубе для добавления новых символов, и пакетный файл никогда не вернется.

Эта проблема изначально привела меня к переполнению стека в этот раз.У меня было 17 000+ команд в командном файле, и каждая команда генерировала 300+ символов для стандартного вывода, а любые ошибки при выполнении команды генерировали 1000+ символов.

Некоторые способы решения этой проблемы:

  1. @echo off в качестве 1-й строки в пакетном файле, при этом процесс cmd не будет отображать каждую команду в пакетном файле.Если ваш пакетный файл не генерирует никаких других выходных данных для stdout или stderr, все готово.

  2. Если одна или несколько команд в пакетном файле могут или могут генерировать много stdout и/ или вывод stderr, тогда вы должны обрабатывать эти данные самостоятельно.

  3. Если вы используете "Runtime.getRuntime (). exec", у вас есть только один способ обработать это,получить InputStreams для stdout и stderr пакетного файла, вызвав:

        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, вы должны также справиться с этим,Это поддерживается в Process и с дополнительными параметрами в ProcessBuilder .

1 голос
/ 23 июня 2011

с выхода 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");
0 голосов
/ 23 июня 2011

Если вы хотите просто узнать, завершен ли процесс пакетного файла или нет, почему бы не добавить ...

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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...