Apache Commons exec PumpStreamHandler непрерывный ввод - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь решить взаимодействие с процессом командной строки, используя Apache Commons exec.Я застрял со следующим кодом:

ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream ins = new ByteArrayOutputStream();
OutputStreamWriter ow = new OutputStreamWriter(ins);
BufferedWriter writer = new BufferedWriter(ow);
ByteArrayInputStream in = new ByteArrayInputStream(ins.toByteArray());
PumpStreamHandler psh = new PumpStreamHandler(out, null, in);
CommandLine cl = CommandLine.parse(initProcess);
DefaultExecutor exec = new DefaultExecutor();
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
exec.setStreamHandler(psh);
try {
    exec.execute(cl, resultHandler);
    int i = 0;
    while (true) {
        String o = out.toString();
        if (!o.trim().isEmpty()) {
            System.out.println(o);
            out.reset();
        }
        // --- PROBLEM start ---
        if (i == 3) {
            writer.write(internalProcessCommand); 
            // string with or without trailing \n, both tested
            writer.flush();
            writer.close();
            // tested even ins.write(internalProcessCommand.getBytes())
        }
        // --- PROBLEM end ---
        Thread.sleep(3000);
        i++;
    }
} catch (ExecuteException e) {
    System.err.println(e.getMessage());
}

Я надеюсь, что мой код ясен.Я постоянно читаю out и печатаю его через 3 секунды при очистке потока.Проблема - это ввод в in, переданный в PumpStreamHandler.Мне нужно передавать команды процесса из самого кода, непрерывно и динамически, как если бы я взаимодействовал с процессом через CLI.Когда я просто использую System.in в качестве аргумента PumpStreamHandler, я могу нормально писать команды процесса из консоли.Как мне получить такой же результат, передавая строки из кода?

Редактировать: Я также пытался подключить PipedInputStream, получая данные от PipedOutputStream, но кажется, что данные можно прочитатьтолько после закрытия PipedOutputStream, что делает его многоразовым, поэтому я не могу достичь интерактивности.

Редактировать 2: Решил сам.Решение в ответе ниже.Howgh.: -)

1 Ответ

0 голосов
/ 18 мая 2018

Хорошо, я решил это с помощью встроенных инструментов, а не внешних библиотек.Я смог достичь своей цели благодаря независимой ветке, которая читает Process 'InputStream:

ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
StreamReader outputReader = new StreamReader(process.getInputStream(), System.out);
outputReader.start();
StreamReader err = new StreamReader(process.getErrorStream(), System.err);
err.start();

for (int i = 0; i < 3; i++) {
    Thread.sleep(5000);
    writer.write(internalProcessCommand + "\n");
    writer.flush();
}
writer.write("exit\n");
writer.flush();

while (process.isAlive()) {
    System.out.println("alive?");
    Thread.sleep(100);
}
System.out.println("dead");
outputReader.shutdown();
err.shutdown();

StreamReader:

class StreamReader extends Thread {

    private AtomicBoolean running = new AtomicBoolean(false);
    private InputStream in;
    private OutputStream out;

    public StreamReader(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
        running.set(true);
    }

    @Override
    public void run() {
        Scanner scanner = new Scanner(in);
        PrintWriter writer = new PrintWriter(out, true);
        while (running.get()) {
            if (scanner.hasNextLine()) {
                writer.println(scanner.nextLine());
            }
        }
        scanner.close();
    }

    public void shutdown() {
        running.set(false);
    }

}
...