Конструктор процессов не принимает входные данные из OutputStream в java - PullRequest
0 голосов
/ 10 июля 2020

У меня есть требование, по которому я буду выполнять командный файл в java. По завершении пакетный сценарий ожидает ввода пользователя. Затем мне нужно передать две команды, за каждой из которых следует клавиша ввода. Пожалуйста, найдите мой код ниже:

        File batchFile = new File("batch file path");            
        ProcessBuilder builder = new ProcessBuilder();
        builder.redirectErrorStream(true);
        builder.command(batchFile.getAbsolutePath());
        Process process = builder.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                process.getInputStream()));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
                process.getOutputStream()));
        String s;
        loop:
        while ((s = reader.readLine()) != null) {
            System.out.println("$: " + s);
            if (s.contains("last line before user input. so i am breaking here")) {
                break loop;
            }
        }
        writer.write("Command1");
        writer.newLine();
        writer.flush();
        writer.write("Command2");
        writer.newLine();
        writer.flush();
        writer.write("/close");
        writer.newLine();
        writer.flush();
        writer.close();
        while ((s = reader.readLine()) != null) {
            System.out.println("$: " + s);
        }

Проблема: Хотя я отправляю ввод через буферную запись, процесс не получает ввод. Может ли кто-нибудь дать мне какие-либо указатели, чтобы исправить эту проблему . Программа работает до последнего, пока l oop. Когда он входит в последний оператор while l oop, он зависает. Похоже, процесс все еще ожидает ввода пользователя, поэтому reader.readLine () в операторе while ждет бесконечно. Целый день искал решение, но все равно не повезло. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 10 июля 2020

Я могу воспроизвести вашу проблему с помощью Windows командных сценариев. Проблема зависит от того, буферизует ли вызываемый вами скрипт свой входной поток или нет.

Ваш скрипт может получать и запускать «Command1», но отбрасывает входной поток на момент чтения следующей строки ввода. - поэтому никогда не читает «Command2» и «/ close» и ждет / зависает для следующей строки. Сценарий MacO C, вероятно, правильно буферизует входные данные.

Вы можете доказать это, выполняя пошаговое выполнение кода в отладчике и делая паузу после каждого writer.newLine();, давая сценарию время для обработки каждой команды, отправляемой из Java приложение. В моем тесте, который позволил второму, пока l oop работал нормально.

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

Команды, которые я использовал для проверки этого, находятся здесь, и я изменил "/ close" на "exit" поэтому можно проверить использование скрипта с буферизацией и без нее.

String[] cmd = new String[] {"cmd.exe", "/c", "cmd_without_buffered_input.cmd"};
String[] cmd = new String[] {"cmd.exe", "/k", "cmd_with_buffered_input.cmd"};
//builder.command(batchFile.getAbsolutePath());

ProcessBuilder builder = new ProcessBuilder(cmd);

cmd_without_buffered_input.cmd - использует set / p для чтения строки за раз и не буферизует ввод

@echo off
setlocal
echo "1"
echo "last line before user input. so i am breaking here"
echo "a"
:loop
set /p id=
echo.
echo Command entered was: %id%
echo  "%id%" == "exit"
if NOT "%id%" == "exit" (
   set id=
   goto:loop
)
echo "BYE"
exit /b

cmd_with_buffered_input.cmd - заканчивается в командной строке CMD.EXE, которая выполняет буферизацию ввода

@echo off
setlocal
echo "1"
echo "last line before user input. so i am breaking here"
echo "BYE"
exit /b
...