2010-07-01 23 views
20

Sto provando ad avviare un processo esternamente con Java e non posso leggere nulla dal suo InputStream.Impossibile leggere InputStream dal processo Java (Runtime.getRuntime(). Exec() o ProcessBuilder)

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 durante il tentativo di lettura. Nessuna informazione è passata attraverso questi flussi in qualsiasi momento.

Qualcuno può spiegare il comportamento? È semplicemente impossibile 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());  
    } 
+0

Hai risolto questo problema? Puoi pubblicare nella soluzione? –

risposta

6

È necessario eseguire 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.

+0

Grazie per la risposta. In realtà l'ho provato all'interno di un thread, in tutte le varianti. Ho provato a leggere intere righe, leggere singoli caratteri e leggere byte. Nessun effetto. Non riesco a ottenere un singolo bit da questo InputStream, e dovrebbe essere decisamente una risposta. Funziona solo se il processo avviato sta terminando (come "ps", "ls"). Ma ho anche bisogno che funzioni con processi "interattivi" come ftp e telnet, ci deve essere un problema di cui non sono a conoscenza. qualche altra idea? – msg

9

Mi rendo conto che questa domanda è vecchia, ma ho appena avuto lo stesso problema. Al fine di risolvere questo problema ho usato questo codice ..

List<String> 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 è in attesa di leggere anche dal flusso di errore. La soluzione migliore è unire insieme flusso di input e di errore.

Aggiornamento

non ho visto che si è tentato di leggere dal flusso di errore anche. Potrebbe essere solo che è necessario unire manualmente con redirectErrorStream(true)

4

ho avuto questo problema con un programma di stampa C stdout ...

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

+0

Questo lo ha risolto per me. Grazie – Darc

1

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. Provare a utilizzare seguente riga di codice per visualizzare il contenuto stderr:

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

Mi ha aiutato a capire cosa era sbagliato con i miei comandi del terminale che attraversa ogni thread.

2

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 degli stream è che non viene scritto nulla.

4

Dopo aver lottato per giorni e aver provato molte opzioni ho trovato una soluzione. Lavorare su Ubuntu 14.04 x64, con jdk 8 u 25.This codereview post mi ha dato il suggerimento.

Il trucco è utilizzare InputStream#available() prima di leggere qualsiasi cosa con lo 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; 
    } 
} 
Problemi correlati