Salut,
J'ai remarqué plusieurs petits problèmes dans ton code :
- Tu utilises waitFor() juste après avoir lancer ton process.
Du coup ton code va bloquer tant que le process ne sera pas terminé.
C'est problématique car tu lis son flux de sortie après.
Si les données envoyées sont de taille réduite ca passera sans problème, mais si le process écrit "trop" de données cela va remplir le buffer entre ton process et ton appli java, et tu va te retrouver dans un double-lock :
- Ton appli Java attendra la fin du process (waitFor()).
- Ton process sera bloqué en écriture à cause du buffer plein.
Il faut bien entendu utiliser waitFor() après la lecture du flux de sortie.
- Tu ne traites pas les flux d'entrée et d'erreur du process. Encore une fois tu risques de bloquer le process s'il les utilise.
Il faut soit les traiter (en parallèle), soit les fermer (ce qui évitera les problèmes de blocage).
Bref pour moi ton code devrait plutôt ressembler à ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private void executeCommand(String directory) {
try {
File dir = new File(directory);
Process p = Runtime.getRuntime()
.exec("cmd /c setgen.bat & XMLGenerator param1 param2",
null, dir);
try {
p.getOutputStream().close();
p.getErrorStream().close();
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line1 = reader.readLine();
while (line1 != null) {
System.out.println(line1);
line1 = reader.readLine();
}
p.waitFor();
} finally {
// perso j'aime bien forcé le destroy "au cas où"
p.destroy();
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
}
} |
Et si tu utilises Java 5.0 ou plus, il serait préférable d'utiliser
ProcessBuilder à la place de
Runtime.exec(), cela permet entre autre de séparer proprement les arguments de la commande, et surtout de rediriger le flux d'erreur dans le flux standard (ce qui permet de ne traiter qu'un flux sans perdre d'éventuel message d'erreur) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private void executeCommand(String directory) {
try {
Process p = new ProcessBuilder("cmd", "/c", "setgen.bat & XMLGenerator param1 param2")
.directory(new File(directory))
.redirectErrorStream(true) // on redirige le flux d'erreur vers le flux de sortie
.start();
try {
p.getOutputStream().close();
p.getErrorStream().close();
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line1 = reader.readLine();
while (line1 != null) {
System.out.println(line1);
line1 = reader.readLine();
}
p.waitFor();
} finally {
// perso j'aime bien forcé le destroy "au cas où"
p.destroy();
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
}
} |
Et avec
Java 7 on peut même utiliser
inheritIO() pour hériter des flux de l'application Java, et du coup plus besoin de les gérer :
1 2 3 4 5 6 7 8 9 10 11
| private void executeCommand(String directory) {
try {
Process p = new ProcessBuilder("cmd", "/c", "setgen.bat & XMLGenerator param1 param2")
.directory(new File(directory))
.inheritIO()
.start();
p.waitFor();
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
}
} |
Note : on peut même paramétrer individuellement chaque flux avec les méthodes redirectXXX()
a++
Partager