Как разблокировать запущенный Java-процесс? - PullRequest
0 голосов
/ 16 апреля 2009

При выполнении некоторой команды (скажем, 'x') из строки cmd я получаю следующее сообщение: "....Нажмите любую клавишу для продолжения . . .". Таким образом, он ожидает, что пользовательский ввод разблокируется.

Но когда я выполняю ту же команду ('x') из Java:

Process p = Runtime.getRuntime().exec(cmd, null, cmdDir);
// here it blocks and cannot use outputstream to write somnething
p.getOutputStream().write(..);

кодовые блоки ...

Я пытался что-то записать в выходной поток процесса, но как я могу это сделать, если код никогда не достигнет этой строки?

Ответы [ 8 ]

2 голосов
/ 16 апреля 2009

Вы должны одновременно читать потоки вывода и ошибок вашего подпроцесса. Размер буфера этих потоков ограничен. Если один из буферов заполнится, подпроцесс заблокируется. Я думаю, что это то, что происходит в вашем случае.

2 голосов
/ 16 апреля 2009

Я думаю (хотя и не уверен), что вы говорите о Windows, а не Unix?

Если это так, возможно, что процесс командной строки на самом деле не ожидает нажатия клавиши (или ввода) на stdin, а вместо этого выполняет эквивалент старой функции DOS kbhit().

AFAIK Нет способа заставить эту функцию поверить, что клавиатура была нажата без фактического нажатия клавиши.

Чтобы проверить эту теорию, создайте текстовый файл «input.txt» с несколькими пустыми строками и запустите:

foo.exe < input.txt

Это покажет, ожидает ли ваша программа stdin или что-то еще.

1 голос
/ 16 апреля 2009

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

//Launch the program
ArrayList<String> command = new ArrayList<String>();
command.add(_program);
command.add(param1);
...
command.add(param1);

ProcessBuilder builder = new ProcessBuilder(command);
//Redirect error stream to output stream
builder.redirectErrorStream(true);

Process process = null;
BufferedReader br = null;
try{
    process = builder.start();

    InputStream is = process.getInputStream();
    br = new BufferedReader( new InputStreamReader(is));
    String line;

    while ((line = br.readLine()) != null) {
         log.add(line);
    }
}catch (IOException e){
    e.printStackTrace();
}finally{
    try{
        br.close();
    }catch (IOException e){
        e.printStackTrace();
    }
}

У объекта процесса есть поток [Input / Output / Error] get, который можно использовать для взаимодействия с программой.

0 голосов
/ 18 ноября 2009

У меня была такая же проблема, и я нашел решение. Это не самый элегантный, но работает.

1 - при выполнении процесса вы получаете inputStream из процесса 2 - Затем вы делаете цикл получения сообщения, показанного в приглашении, если оно было 3 - Когда вы видите, что получили из «подсказки» «нажать клавишу для продолжения» или что-то еще, вы завершаете процесс

            // Creates the runtime and calls the command
        Process proc = Runtime.getRuntime().exec(Destino);

        // Get the proccess inputStream
        InputStream ips = proc.getInputStream();
        String output = "";

        int c = 0;

        // Read the output of the pro
        while ((c = ips.read()) != -1
                && !output.contains("Press any key to continue")) {
            output = output + (char)c;
        }

        // Destroy the proccess when you get the desired message
        proc.destroy();
0 голосов
/ 16 апреля 2009

Используйте PrintWriter для имитации ввода:

        Process p = Runtime.getRuntime().exec(cmd, null, cmdDir);
        //consume the proces's input stream
        ........
        // deblock
        OutputStream outputStream = p.getOutputStream();
        PrintWriter pw = new PrintWriter(outputStream);
        pw.write("ok");
        pw.flush();
        int errCode = p.waitFor();
0 голосов
/ 16 апреля 2009

Итак, это мой обходной путь к этой проблеме, вдохновленный предложением Альнитака: Запустите команду так:

Process p = Runtime.getRuntime().exec(cmd + " < c:\\someTextFile.txt", null, cmdDir);
...
int errCode = p.waitFor();
...

'someTextFile.txt' может быть программно создан во временном каталоге, а затем удален.

0 голосов
/ 16 апреля 2009

Я написал ответ на выполнение командной строки на этот вопрос стекопотока .

С вами немного сложнее, потому что вам, вероятно, нужно ответить.

В вашем случае может потребоваться дать гоблеру входного потока что-то вроде канала ответа:

 StreamGobbler outputGobbler = new StreamGobbler(
                                    proc.getInputStream(), "OUTPUT", 
                                    proc.getOutputStream());

и сопоставить его с шаблоном и ответом в заданном входном потоке.

while ((line = br.readLine()) != null) {
    System.out.println(type + ">" + line);
    if (line.contains(PRESS_KEY_CONTINUE) {
        ostream.write("y".getBytes("US-ASCII")); 
        System.out.println("< y"); 
    }
}

Надеюсь, это поможет.

0 голосов
/ 16 апреля 2009

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

Один из вариантов - запустить внешний процесс в отдельном потоке или использовать потоки, совместно использующие Process p, чтобы иметь возможность записи в его поток.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...