Запустите внешний исполняемый файл из кода Java с перенаправлением потоков - PullRequest
6 голосов
/ 20 ноября 2010

Мне нужно запустить внешний исполняемый файл таким образом, чтобы пользователь мог взаимодействовать с только что запущенной программой.

Например, в OpenSuse Linux есть менеджер пакетов - Zypper. Вы можете запустить zypper в командном режиме и дать ему такие команды, как установка, обновление, удаление и т. Д.

Я хотел бы запустить его из кода Java так, чтобы пользователь мог взаимодействовать с ним: вводить команды и видеть вывод и ошибки программы, которую он запустил.

Вот код Java, который я пытался использовать:

public static void main(String[] args) throws IOException, InterruptedException {
    Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");

    InputStream stderr = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stderr);
    BufferedReader br = new BufferedReader(isr);
    String line = null;
    char ch;

    while ( (ch = (char)br.read()) != -1)
        System.out.print(ch);

    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
}

Но, к сожалению, я вижу только вывод:

zypper>

но что бы я ни писал, мой ввод не влияет на запущенную программу. Как я могу делать то, что хочешь?

Ответы [ 3 ]

2 голосов
/ 20 ноября 2010

Вам нужно получить выходной поток для записи в процесс:

OutputStream out = proc.getOuptutStream();

Этот поток вывода передается в стандартный поток ввода процесса, так что вы можете просто записать в него (возможно, вы хотите сначала обернуть его в PrintWriter), и данные будут отправлены в stdin процесса.

Обратите внимание, что также может быть удобно получить поток ошибок (proc.getErrorStream), чтобы прочитать любой вывод ошибок, который процесс записывает в свой stderr.

Ссылка API:

0 голосов
/ 21 ноября 2010

Я недавно обернул Google Closure Compiler в .jar-файл, который извлекается и используется в Процессе. Этот компилятор говорит только через System.in/out/err. В соединяющих друг с другом каналах есть большой "недочет", который кратко упоминается в javadoc Process.

"... не удалось быстро написать входной поток или чтение выходного потока подпроцесса может вызвать подпроцесс для блокировки, и даже тупиковой. "* +1004 *

В Mac OS X размер буфера составляет 16 Кбайт, и если вы не прочитаете его быстро, как это было предложено, процесс заблокируется. Мое единственное решение этой проблемы банкомат, довольно неприятное занятое ожидание.

https://github.com/algesten/googccwrap/blob/master/src/main/java/googccwrap/GoogleClosureCompilerWrapper.java

0 голосов
/ 20 ноября 2010

Похоже, что преобразование внутри условия while не выполняется в вашем примере, похоже, это работает лучше (я не запускаю Suse, поэтому я не пробовал с Zypper):

public static void main(String[] args) throws IOException, InterruptedException
{
    //Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");
    Process proc = java.lang.Runtime.getRuntime().exec("ping -t localhost");

    InputStream stderr = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stderr);
    BufferedReader br = new BufferedReader(isr);

    int i;
    while ( (i = br.read()) != -1)
    {
        System.out.print((char) i);
    }

    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
}
...