Запустите bat файл на Java и подождите 2 - PullRequest
2 голосов
/ 15 марта 2010

Это следующий вопрос к моему другому вопросу: Запустите bat-файл на Java и подождите

Причина, по которой я выкладываю это как отдельный вопрос, состоит в том, что на тот, который я уже задал, был дан правильный ответ Из некоторых исследований я сделал мою проблему уникальной для моего случая, поэтому я решил создать новый вопрос. Пожалуйста, прочитайте этот вопрос, прежде чем продолжить с этим, поскольку они тесно связаны.

Запуск предложенного кода блокирует программу при вызове waitFor. После некоторых исследований я обнаружил, что метод waitFor блокирует, если у вашего процесса есть выходные данные, которые необходимо обработать, поэтому сначала нужно очистить поток вывода и поток ошибок. Я делал эти вещи, но мой метод все еще блокирует. Затем я обнаружил предложение просто зацикливаться, ожидая, когда метод exitValue вернет выходное значение процесса и обработает выброшенное исключение, если это не так, делая паузу на короткое время, а также чтобы не использовать весь процессор. Я сделал это:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test {

 public static void main(String[] args) {
  try {
   Process p = Runtime.getRuntime().exec(
     "cmd /k start SQLScriptsToRun.bat" + " -UuserName -Ppassword"
       + " projectName");
   final BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
   final BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
   new Thread(new Runnable() {

    @Override
    public void run() {
     try {
      while (input.readLine()!=null) {}
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
   }).start();
   new Thread(new Runnable() {

    @Override
    public void run() {
     try {
      while (error.readLine()!=null) {}
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
   }).start();
   int i = 0;
   boolean finished = false;
   while (!finished) {
    try { 
     i = p.exitValue();
     finished = true;
    } catch (IllegalThreadStateException e) {
     e.printStackTrace();
     try {
      Thread.sleep(500);
     } catch (InterruptedException e1) {
      e1.printStackTrace();
     }
    }
   }
   System.out.println(i);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

но мой процесс не закончится! Я получаю эту ошибку:

java.lang.IllegalThreadStateException: process has not exited

Есть идеи, почему мой процесс не завершится? Или у вас есть какие-либо библиотеки, которые предлагают правильно обрабатывать пакетные файлы и ждать, пока выполнение не будет завершено?

1 Ответ

4 голосов
/ 15 марта 2010

Запустите cmd с помощью переключателя /c вместо /k и избавьтесь от start:

Process p = Runtime.getRuntime().exec( 
   "cmd /c SQLScriptsToRun.bat" + " -UuserName -Ppassword" 
   + " projectName");

/k говорит cmd: «Запустите эту команду и затем оставайтесь открытым», в то время как /c говорит «Выполните эту команду и затем выйдите».

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

Однако ваша главная проблема в том, что вы создаете еще один процесс с использованием start. Чтобы запустить пакетный файл, это совершенно не нужно и не позволяет вам знать, когда пакет был запущен полностью, поскольку Java имеет ссылку на исходный cmd процесс, который вы запустили, а не тот, который вы породили start.

В принципе, теперь это выглядит следующим образом:

  1. Java-программа запускается
  2. Java-программа запускает cmd и дает ей команду start foo.bat и остается открытой для интерактивного ввода (/k)
  3. Java запоминает идентификатор процесса (PID 42) для последующей ссылки на этот процесс

    • cmd (PID 42) запускается
    • cmd (PID 42) работает start foo.bat
    • start foo.bat запускает еще один экземпляр cmd, поскольку именно так должно происходить при запуске командных файлов
      • cmd (PID 57005) запускается
      • cmd (PID 57005) работает foo.bat
      • cmd (PID 57005) выходит (отмечает событие, о котором вы хотели бы знать)
    • cmd (PID 42) показывает подсказку и послушно ждет ввода (без ведома пользователя подсказка никогда не просматривается пользователем, и ввод никогда не поступит ... но cmd (PID 42) ждет .. .)
  4. Java любит знать, завершен ли процесс, и проверяет PID 42

  5. Да, это все еще там. И что теперь?

То, что вы хотите (и что приведут выше изменения):

  1. Java-программа запускается
  2. Java-программа запускает cmd и выдает команду на запуск foo.bat и закрытие после выполнения команды (/c)
  3. Java запоминает идентификатор процесса (PID 42) для последующей ссылки на этот процесс

    • cmd (PID 42) запускается
    • cmd (PID 42) работает foo.bat
    • cmd (PID 42) выход
  4. Java любит знать, завершен ли процесс, и проверяет PID 42

  5. Ура, процесс завершен, пакетный файл запущен.
...