2010-07-01 3 views
20

Я пытаюсь запустить процесс извне с Java и ничего не могу прочитать из его InputStream.Невозможно прочитать InputStream из Java Process (Runtime.getRuntime(). Exec() или ProcessBuilder)

Если я начинаю процесс с такими командами, как «ls», «ps» или «kill», все работает нормально. Я могу запустить процесс и получить информацию либо на InputStream, либо на ErrorStream процесса.

Если я пытаюсь использовать команду «ftp» или «telnet», как InputStream, так и ErrorStream блокируют мою программу при попытке прочитать. Никакая информация не передается через эти потоки в любое время.

Может ли кто-нибудь объяснить поведение? Это просто невозможно с этими командами или у меня проблема с моей реализацией?

 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

Вы поняли эту проблему? Можете ли вы опубликовать в своем решении? –

ответ

6

Вам необходимо сделать эту работу в теме. Например, для регистрации стандартного вывода:

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(); 
     } 
    } 
} 

Тогда вам понадобится второй поток для обработки ввода. И вы можете иметь дело с stderr так же, как stdout.

+0

Благодарим вас за ответ. На самом деле я тестировал его в потоке во всех вариантах. Я пробовал читать целые строки, читая отдельные символы и считывая байты. Нет эффекта. Я не могу получить ни одного бита из этого InputStream, и он должен обязательно отвечать. Он работает только в том случае, если запущенный процесс завершается (например, «ps», «ls»). Но мне также нужно, чтобы он работал с «интерактивными» процессами, такими как ftp и telnet, должна быть проблема, о которой я не знаю. любые более новые идеи? – msg

9

Я понимаю, что это вопрос старый, но я просто испытал ту же проблему. Для того, чтобы исправить это, я использовал этот код ..

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(); 

Похоже, процесс ожидает Вас также чтения из потока ошибок. Лучшее решение для этого - объединить поток ввода и ошибки вместе.

Update

Я не видел, что вы пытались прочитать из потока ошибок тоже. Это может быть просто, что вам нужно объединить их вручную с помощью redirectErrorStream(true)

4

Я имел этот вопрос с печатью программы C на стандартный вывод ...

redirectErrorStream(true) раствор с fflush(stdout) в коде C сделал трюк для меня ,

+0

Это исправлено для меня. благодаря – Darc

1

У меня была такая же проблема. К сожалению,

processBuilder.redirectErrorStream(true); 

не работает для меня; это дало мне представление о том, что не так. Попробуйте использовать следующую строку коды для отображения Stderr содержания:

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

Это помогло мне понять, что случилось с моими клеммными командами, проходящих через каждый поток.

2

У меня была такая же проблема с ftp, пока я не заметил, что ftp обнаруживает, вызван ли он с терминала или нет.

Когда ftp не вызывается с терминала, он приостанавливает любой вывод на stdout, если не указана опция verbose (-v).

Причина блокировки потоков заключается в том, что им ничего не написано.

4

После долгих дней и попыток много вариантов Я нашел решение. Работает на Ubuntu 14.04 x64, с jdk 8 u 25.This codereview post дал мне подсказку.

Хитрость заключается в использовании InputStream#available() перед чтением чего-либо с помощью BufferedReader. У меня лично есть два потока: один для stdout и другой для stderr. Вот простой исполняемый фрагмент, который я экстраполировал из своей программы. Если вы не хотите читать все, просто перейдите на страницу 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; 
    } 
} 
Смежные вопросы