java - process.waitFor() nunca devuelve
runtime.exec (8)
Como otros han mencionado, debes consumir stderr y stdout .
En comparación con las otras respuestas, desde Java 1.7 es aún más fácil. Ya no tiene que crear subprocesos para leer stderr y stdout .
Solo use ProcessBuilder
y use los métodos redirectOutput
en combinación con redirectError
o redirectErrorStream
.
String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) {
builder.redirectErrorStream(true); // Combine stderr into stdout
} else {
builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
Creo que observé un problema similar: algunos procesos comenzaron, parecían funcionar con éxito pero nunca se completaron. La función waitFor () estaba esperando para siempre, excepto si eliminé el proceso en el Administrador de tareas.
Sin embargo, todo funcionó bien en los casos en que la longitud de la línea de comando era de 127 caracteres o menos. Si los nombres de archivo largos son inevitables, es posible que desee utilizar variables de entorno, que pueden permitirle mantener corta la línea de comando. Puede generar un archivo por lotes (utilizando FileWriter) en el que establece sus variables de entorno antes de llamar al programa que realmente desea ejecutar. El contenido de dicho lote podría verse así:
set INPUTFILE="C:/Directory 0/Subdirectory 1/AnyFileName"
set OUTPUTFILE="C:/Directory 2/Subdirectory 3/AnotherFileName"
set MYPROG="C:/Directory 4/Subdirectory 5/ExecutableFileName.exe"
%MYPROG% %INPUTFILE% %OUTPUTFILE%
El último paso es ejecutar este archivo por lotes utilizando Runtime.
Hay muchas razones por las cuales waitFor()
no regresa.
Pero generalmente se reduce al hecho de que el comando ejecutado no se cierra.
Esto, nuevamente, puede tener muchas razones.
Una razón común es que el proceso produce algunos resultados y no lee de los flujos apropiados. Esto significa que el proceso se bloquea tan pronto como el búfer está lleno y espera a que su proceso continúe leyendo. Su proceso a su vez espera que termine el otro proceso (que no lo hará porque espera su proceso, ...). Esta es una situación clásica de estancamiento.
Necesita leer continuamente de la secuencia de entrada de procesos para asegurarse de que no se bloquee.
Hay un buen artículo que explica todas las trampas de Runtime.exec()
y muestra formas de evitarlo llamadas "Cuando Runtime.exec () no" (sí, el artículo es de 2000, ¡pero el contenido aún se aplica!)
Hay varias posibilidades:
- No ha consumido todo el resultado en la salida
stdout
del proceso. - No ha consumido toda la salida en el proceso
stderr
. - El proceso está esperando la entrada de usted y no lo ha proporcionado, o no ha cerrado el
stdin
del proceso. - El proceso está girando en un ciclo difícil.
Me gustaría agregar algo a las respuestas anteriores, pero como no tengo el representante para comentar, solo agregaré una respuesta. Esto está dirigido a usuarios de Android que están programando en Java.
Según la publicación de RollingBoy, este código casi funcionó para mí:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
En mi caso, waitFor () no estaba lanzando porque estaba ejecutando una declaración sin devolución ("ip adddr flush eth0"). Una manera fácil de solucionar esto es simplemente asegurarse de que siempre devuelva algo en su extracto. Para mí, eso significaba ejecutar lo siguiente: "ip adddr flush eth0 && echo done". Puede leer el búfer todo el día, pero si no devuelve nada, su hilo nunca liberará su espera.
Espero que ayude a alguien!
Parece que no estás leyendo la salida antes de esperar a que termine. Esto está bien solo si la salida no llena el búfer. Si lo hace, esperará hasta que lea la salida, catch-22.
Tal vez tengas algunos errores que no estás leyendo. En este caso, la aplicación se detendrá y esperará para esperar para siempre. Una forma sencilla de evitar esto es redirigir los errores al resultado regular.
ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("tasklist: " + line);
process.waitFor();
Por la misma razón, también puede usar inheritIO()
para asignar la consola de Java con una consola de aplicación externa como:
ProcessBuilder pb = new ProcessBuilder(appPath, arguments);
pb.directory(new File(appFile.getParent()));
pb.inheritIO();
Process process = pb.start();
int success = process.waitFor();
También desde el documento de Java:
java.lang
Proceso de clase
Debido a que algunas plataformas nativas solo proporcionan un tamaño de búfer limitado para flujos de entrada y salida estándar, si no se escribe rápidamente el flujo de entrada o se lee el flujo de salida del subproceso, es posible que el subproceso se bloquee e incluso se bloquee.
Si no se borra el búfer de la corriente de entrada (que conduce a la corriente de salida del subproceso) desde el proceso puede conducir a un bloqueo del subproceso.
Prueba esto:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();