2017-02-05 4 views
0

Я использую ProcessBuilder для запуска инструмента командной строки, который мы используем. Во время запуска инструмент задает два вопроса «да/нет», поэтому обычно я дважды отвечаю «y», а затем каждый раз нажимаю клавишу ввода. Моя проблема в том, что инструмент всегда заканчивает выполнение при запуске с cmd, но когда я запускаю его через свой Java-код, он иногда работает и иногда застревает на while ((n = op.read(buffer)) != -1) (с тем же вводом).ProcessBuilder BufferedReader read() blocking

Вот мой код. Я делаю что-то неправильно? Что мне не хватает? Благодарю.

List<String> processArgs = new ArrayList<>(); 
processArgs.add(0, "java"); 
processArgs.add(1, "-jar"); 
processArgs.add(2, JAR_PATH); 
processArgs.add(3, "-put"); 
processArgs.addAll(args); 
try 
{ 
    // run tool with put 
    ProcessBuilder pb = new ProcessBuilder(processArgs); 
    pb.directory(new File("src\\temp")); 
    pb.redirectErrorStream(true); 
    Process p = pb.start(); 

    // write 'y' to the tool's stdin. 
    String answer = "y" + System.getProperty("line.separator"); 
    // yes to first question 
    p.getOutputStream().write(answer.getBytes()); 
    p.getOutputStream().flush(); 

    // read tool's process stdout 
    this.op = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    StringWriter sw = new StringWriter(); 
    int n = 0; 
    boolean answered = false; 
    char[] buffer = new char[BUFFER_SIZE]; 
    while ((n = op.read(buffer)) != -1) 
    { 
     sw.write(buffer, 0, n); 
     if (sw.toString().contains("second question") && !answered) 
     { 
      // yes to second question 
      p.getOutputStream().write(answer.getBytes()); 
      p.getOutputStream().flush(); 
      answered = true; 
     } 
    } 

    stdout = sw.toString(); 
    exitCode = p.waitFor(); 
} 
catch (IOException | InterruptedException e) 
{ 
    throw new ToolException("process had an exception:\n" + e.getMessage()); 
} 

UPDATE: Я изменил код и добавил pb.redirectErrorStream(true), но теперь этот процесс еще будет заблокирован на op.read(buffer). Когда я отлаживаю, кажется, что он застрял во втором вопросе, хотя я дважды писал «y» в выходной поток. Использую ли я getOutputStream() неправильно?

ВТОРОЕ ОБНОВЛЕНИЕ: Второй вопрос не получил второй «y» в качестве ответа, и это заставило процесс ждать ввода. Я изменил код, поэтому я покажу правильный способ вставки ввода в выходной поток subprocess.

ответ

2

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

Простым решением является перенаправление ошибки на выход, поэтому у вас есть только один поток для чтения. т.е.

pb.redirectErrorStream(true); 

В соответствии с документацией https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html

альтернативы включают; запись ошибки в файл или чтение ее в другом потоке.

+0

Спасибо, много, Питер, это помогло, но я все равно заблокирован на read(). См. Мое обновление. – gamlieldor

+0

@gamlieldor Я предлагаю вам распечатать вывод по мере его запуска. Скорее всего, нас ждет вход. –

+0

Я сделал, и вы правы, он ждет ввода по второму вопросу. Как заставить его принимать «y» ответы один раз для первого вопроса и один раз для второго? Я попытался перенаправить вход pb в файл с «y», разделенным новыми строками, но это не помогло. – gamlieldor

Смежные вопросы