Невозможно прочитать InputStream из Java-процесса (Runtime.getRuntime (). Exec () или ProcessBuilder) - PullRequest
21 голосов
/ 01 июля 2010

Я пытаюсь запустить процесс извне с помощью Java и не могу прочитать что-либо из его InputStream.

Если я запускаю процесс с такими командами, как "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());     
   } 

Ответы [ 6 ]

11 голосов
/ 10 февраля 2011

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

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

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

Обновление

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

6 голосов
/ 12 июля 2011

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

Решение redirectErrorStream(true) с fflush(stdout) в коде C помогло мне.

6 голосов
/ 01 июля 2010

Вы должны сделать эту работу в потоке.Например, чтобы записать стандартный вывод:

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.

4 голосов
/ 24 января 2015

Поработав несколько дней и попробовав множество вариантов Я нашел решение . Работа над Ubuntu 14.04 x64, с jdk 8 u 25. Этот пост-обзор кода дал мне подсказку.

Хитрость в том, чтобы использовать 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;
    }
}
2 голосов
/ 22 февраля 2013

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

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

Причиной блокировки потоков является то, что им ничего не пишется.

1 голос
/ 07 июня 2012

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

processBuilder.redirectErrorStream(true); 

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

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

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

...