2010-03-15 8 views
2

Ceci est une question de suivi à mon autre question: Run bat file in Java and waitExécuter fichier bat en Java et attendez 2

La raison pour laquelle je suis annonce cela comme une question distincte est que celui que je déjà demandé a été répondu correctement. De certaines recherches j'ai fait mon problème est unique à mon cas, j'ai donc décidé de créer une nouvelle question. S'il vous plaît allez lire cette question avant de continuer avec celui-ci car ils sont étroitement liés.

L'exécution du code proposé bloque le programme lors de l'appel waitFor. Après quelques recherches, j'ai trouvé que la méthode waitFor bloque si votre processus a une sortie qui doit être traitée, donc vous devez d'abord vider le flux de sortie et le flux d'erreurs. J'ai fait ces choses mais ma méthode bloque toujours. J'ai alors trouvé une suggestion de simplement boucler en attendant la méthode exitValue pour retourner la valeur de sortie du processus et gérer l'exception levée si ce n'est pas le cas, en faisant une pause pendant un bref instant pour ne pas consommer tout le CPU. Je l'ai fait:

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

mais mon processus ne se terminera pas! Je continue à obtenir cette erreur:

java.lang.IllegalThreadStateException: process has not exited 

Des idées sur la raison pour laquelle mon processus ne va pas quitter? Ou avez-vous des bibliothèques à suggérer qui gèrent l'exécution correcte des fichiers batch et attendent que l'exécution soit terminée?

Répondre

3

Démarrer cmd avec le /c commutateur au lieu de /k et de se débarrasser de la start:

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

/k dit cmd: « Exécuter cette commande puis rester ouvert », tandis que /c dit « Exécuter cette commande puis exit. "

/k est à usage interactif si vous voulez un fichier batch d'initialisation et utilisez ensuite la console.

Votre principal problème ici, cependant, est que vous créez encore un autre processus en utilisant start. Pour exécuter un fichier batch, ceci est totalement inutile et vous empêche de savoir quand le batch a été exécuté complètement, puisque Java fait référence au processus original cmd que vous avez démarré, pas à celui que vous avez créé avec start.

En principe, cela ressemble maintenant à ce qui suit:

  1. programme Java commence
  2. programme Java fonctionne cmd et hsearch courir start foo.bat et rester ouvert pour l'entrée interactive (/k)
  3. Java mémorise l'ID de processus (PID 42) pour faire référence ultérieurement à ce processus

    • cmd (PID 42) commence
    • cmd (PID 42) exécute start foo.bat
    • start foo.bat lance une autre instance de cmd, puisque c'est ce qui devrait arriver d'exécuter des fichiers batch
      • cmd (PID 57005) commence
      • cmd (PID 57005) s'exécute foo.bat
      • cmd (PID 57005) quitte (Ceci marque l'événement que vous aimeriez connaître)
    • cmd (PID 42) montre l'invite et attend docilement pour l'entrée (à leur insu l'invite est jamais vu par un utilisateur et aucune entrée ne viendra jamais ... mais cmd (PID 42) attend .. .)
  4. Java aime savoir si le processus est terminé et contrôle PID 42

  5. Eh oui, il est toujours là. Maintenant quoi?

Qu'est-ce que vous voulez (et ce ci-dessus le changement fera) est la suivante:

  1. programme Java commence
  2. programme Java fonctionne cmd et il ordonne d'exécuter foo.bat et à proximité après l'exécution de la commande (/c)
  3. Java mémorise l'identificateur de processus (PID 42) pour référence ultérieure qui traitent

    • cmd (PID 42) commence
    • cmd (PID 42) exécute foo.bat
    • cmd (PID 42) sort
  4. Java aime savoir si le processus est terminé et contrôle PID 42

  5. Hourra, le processus est parti, le fichier batch a été exécuté.
+0

cela entraînerait la sortie immédiate du processus. Ce que je veux, c'est attendre que cela soit fait. –

+0

@sav: Supprime également le 'start'. – Joey

+0

Oui bien j'ai pensé à cela mais malheureusement si vous l'essayez vous-même vous verrez qu'il n'exécutera pas le fichier bat ... J'ai essayé toutes les combinaisons. Aucun ne fonctionne. Certains bloqueront pour toujours, d'autres n'amèneront pas du tout la fenêtre de cmd ... –

Questions connexes