2011-10-13 7 views
5

Mi piacerebbe ottenere l'output da un comando shell di lunga esecuzione in quanto è disponibile anziché attendere il completamento del comando. Il mio codice viene eseguito in un nuovo threadUscita asincrona Java Runtime.exec()

Process proc = Runtime.getRuntime().exec("/opt/bin/longRunning"); 
InputStream in = proc.getInputStream(); 
int c; 
while((c = in.read()) != -1) { 
    MyStaticClass.stringBuilder.append(c); 
} 

Il problema di questo è che il mio programma in/opt/bin/longRunning deve completare prima che l'InputStream viene assegnato e leggere. C'è un buon modo per farlo in modo asincrono? Il mio obiettivo è che una richiesta Ajax restituirà il valore corrente MyStaticClass.stringBuilder.toString() ogni secondo circa.

Sono bloccato su Java 5, fyi.

Grazie! W

+0

Grazie a tutti! L'Exec di Apache Commons è il modo in cui sono andato. @Paul Cager, hai anche fornito un'idea eccellente. Lo script che veniva chiamato stava infatti rilevando che era in corso il piping e il blocco. Tuttavia il flusso che si ottiene da Runtime.exec è sincronizzato, quindi se si tenta di leggerlo, si sta bloccando. – wmarbut

risposta

7

Provare con Apache Common Exec. Ha la capacità di eseguire in modo asincrono un processo e quindi "pompare" l'output su un thread. Controllare il Javadoc per ulteriori informazioni

1

Runtime.getRuntime(). Exec fa non attendi che il comando termini, quindi dovresti ricevere subito l'output. Forse l'output viene bufferizzato perché il comando sa che sta scrivendo su una pipe piuttosto che su un terminale?

1

Mettere la lettura in un nuovo thread:

new Thread() { 
    public void run() { 
     InputStream in = proc.getInputStream(); 
     int c; 
     while((c = in.read()) != -1) { 
      MyStaticClass.stringBuilder.append(c); 
     } 
    } 
}.start(); 
+0

Qui potrei essere un po 'stupido, ma come faresti a togliere la variabile c dal thread? Inoltre, non dovrebbe essere una stringa? –

2

Ti è scrivere il programma che si sta chiamando? In tal caso, prova a svuotare l'output dopo la scrittura. Il testo potrebbe essere bloccato in un buffer e non accedere al tuo programma java.

Io uso questo codice per fare questo e funziona:

Runtime runtime = Runtime.getRuntime(); 
    Process proc = runtime.exec(command); 
    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); 

    while (true) { 

     // enter a loop where we read what the program has to say and wait for it to finish 
     // read all the program has to say 
     while (br.ready()) { 
      String line = br.readLine(); 
      System.out.println("CMD: " + line); 
     } 

     try { 
      int exitCode = proc.exitValue(); 
      System.out.println("exit code: " + exitCode); 
      // if we get here then the process finished executing 
      break; 
     } catch (IllegalThreadStateException ex) { 
      // ignore 
     } 

     // wait 200ms and try again 
     Thread.sleep(200); 

    } 
+0

BufferedReader.ready() copre anche lo stato di BufferedReader.readLine()? La documentazione menziona solo che ready() indica quando read() può essere usato, readLine() sarà probabilmente un paio di operazioni read(), quindi questo approccio potrebbe ancora bloccarsi come ho capito. – bcause

+0

Hai ragione, bloccherà e rimarrà in questo loop fino a quando non verrà terminato il processo secondario. Questo è corretto secondo me. Se vuoi fare qualcos'altro prima che il programma finisca di girare, metti questo codice in un thread separato e fai l'altro lavoro in un thread diverso. Non vedo un modo per rendere InputStream restituito da Process non bloccante come si può fare con i socket di rete. In tal caso, genererebbe un'eccezione di timeout quando si tenta di leggere dallo stream. –

0

provare:

try { 
     Process p = Runtime.getRuntime().exec("/opt/bin/longRunning"); 
     BufferedReader in = new BufferedReader( 
            new InputStreamReader(p.getInputStream())); 
     String line = null; 
     while ((line = in.readLine()) != null) { 
     System.out.println(line); }