Imansible leggere InputStream dal processo Java (Runtime.getRuntime (). Exec () o ProcessBuilder)

Sto cercando di avviare un processo esternamente con Java e non posso leggere nulla dal suo InputStream.

Se sto iniziando un processo con comandi come “ls”, “ps” o “kill”, tutto funziona correttamente. Posso avviare il processo e ottenere informazioni su InputStream o ErrorStream del processo.

Se provo a utilizzare un comando come “ftp” o “telnet”, sia InputStream che ErrorStream bloccano il mio programma quando provo a leggere. Nessuna informazione è passata attraverso questi flussi in qualsiasi momento.

Qualcuno può spiegare il comportamento? È semplicemente imansible con questi comandi o ho un problema con la mia implementazione?

String processName = _configuration.getProgramCommand().getCommand(); ProcessBuilder procBuilder = new ProcessBuilder(processName); System.out.println("Starting process "+processName); _proc = Runtime.getRuntime().exec(processName);// procBuilder.start(); if(!procBuilder.redirectErrorStream()) { _errorWorker = new ProcessErrorWorker(_proc); _errorWorker.start(); } String proc_start_answer = _configuration.getNextCommand().getCommand(); System.out.println("Waiting for process answer '"+proc_start_answer+"'"); BufferedReader input = new BufferedReader(new InputStreamReader(_proc.getInputStream())); String answer = ""; try { System.out.println("inputstream ready: "+input.ready()); answer+=input.readLine(); System.out.println("process answer: "+answer); input.close(); } catch(Exception e) { System.out.print(e.getMessage()); } 

Mi rendo conto che questa è una domanda vecchia, ma ho vissuto lo stesso problema. Per risolvere questo problema ho usato questo codice ..

  List commandAndParameters = ...; File dir = ...; // CWD for process ProcessBuilder builder = new ProcessBuilder(); builder.redirectErrorStream(true); // This is the important part builder.command(commandAndParameters); builder.directory(dir); Process process = builder.start(); InputStream is = process.getInputStream(); 

Sembra che il processo ti aspetti di leggere anche dal stream degli errori. La soluzione migliore è unire insieme stream di input e di errore.

Aggiornare

Non ho visto che hai tentato di leggere anche il stream degli errori. Potrebbe semplicemente essere necessario unirli manualmente con redirectErrorStream(true)

Devi fare questo lavoro in una discussione. Ad esempio per registrare lo standard output:

 Process process = Runtime.getRuntime().exec(command); LogStreamReader lsr = new LogStreamReader(process.getInputStream()); Thread thread = new Thread(lsr, "LogStreamReader"); thread.start(); public class LogStreamReader implements Runnable { private BufferedReader reader; public LogStreamReader(InputStream is) { this.reader = new BufferedReader(new InputStreamReader(is)); } public void run() { try { String line = reader.readLine(); while (line != null) { System.out.println(line); line = reader.readLine(); } reader.close(); } catch (IOException e) { e.printStackTrace(); } } } 

Quindi è necessario un secondo thread per la gestione degli input. E potresti voler trattare con stderr proprio come stdout.

Ho avuto questo problema con un programma C che stampa sullo stdout …

La soluzione redirectErrorStream(true) con fflush(stdout) nel codice C ha fatto il trucco per me.

Dopo aver lottato per giorni e aver provato molte opzioni, ho trovato una soluzione . Lavorando su Ubuntu 14.04 x64, con jdk 8 u 25. Questo post di visualizzazione di codice mi ha dato il suggerimento.

Il trucco è usare InputStream#available() prima di leggere qualsiasi cosa con BufferedReader . Personalmente ho due thread, uno per lo stdout e l’altro per lo stderr. Ecco un semplice frammento di esecuzione che ho estrapolato dal mio programma. Se non vuoi leggere tutto, passa a readLine()

 import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStreamReader; import java.io.InputStream; import java.io.BufferedReader; import java.nio.charset.Charset; public class LogHandler { private BufferedReader bufferedReader; private InputStream inputStream; private Thread thread; private boolean isRunning; public void open (InputStream inputStream) { this.inputStream = inputStream; this.bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset())); isRunning = true ; if(thread!=null){ thread = new Thread (()->{ while(isRunning) { String line = null; try { line = readLine(); } catch (IOException e) { isRunning = false; } if(line == null) { try { Thread.sleep(150); } catch (InterruptedException ie) { isRunning=false; Thread.currentThread().interrupt(); } } else { System.out.println(line); } } }); } else throw new IllegalStateException("The logger is already running"); thread.start(); } public void close() throws InterruptedException { if(thread!=null){ thread.interrupt(); thread.join(); thread = null; IOUtils.closeQuietly(inputStream); } else throw new IllegalStateException("The logger is not running"); } private String readLine() throws IOException { if(inputStream.available()>0) { // <--------- THIS IS IT int kar = bufferedReader.read(); if (kar != -1) { StringBuilder buffer = new StringBuilder(30); while (kar != -1 && kar != (int) '\n') { buffer.append((char) kar); kar = bufferedReader.read(); } return buffer.toString(); } } return null; } } 

Ho avuto lo stesso problema con ftp, fino a quando ho notato che ftp rileva se è chiamato da un terminale o meno.

Quando ftp non viene chiamato da un terminale, sospende qualsiasi output su stdout, a meno che non venga fornita l’opzione verbose (-v).

Il motivo del blocco dei flussi è che non viene scritto nulla per loro.

Ho avuto lo stesso identico problema. purtroppo

 processBuilder.redirectErrorStream(true); 

non ha funzionato per me; mi ha dato un’idea di cosa c’è che non va. Prova a utilizzare la seguente riga di codice per visualizzare i contenuti di stderr:

 BufferedReader err= new BufferedReader(new InputStreamReader(process.getErrorStream())); 

Mi ha aiutato a capire cosa c’era di sbagliato con i miei comandi del terminale che passavano attraverso ogni thread.