Как я могу получить обратный вызов о готовности stdout / stderr вместо опроса занятости? - PullRequest
0 голосов
/ 02 ноября 2018

Все обсуждения, которые я нашел при чтении из Process stdout, делают это блокирующим образом, как здесь:

Process process=Runtime.getRuntime().exec(cmd);
BufferedReader in=new BufferedReader(
    new InputStreamReader(process.getInputStream()));
for(String line;(line=in.readLine())!=null;)
{
    useText(line);
}

Если я пытаюсь избежать блокировки, я могу опрашивать поток, используя in.ready().

Но что мне действительно нужно, так это оставить процесс запущенным и сделать что-то полезное, и пытаться читать что-либо только тогда, когда данные действительно доступны. Поэтому я ищу что-то вроде сигнала Qt QProcess::readyReadStandardOutput. Обратите внимание, что BufferedReader nethod ready - это не то, что я ищу: это просто метод, который мне придется неоднократно проверять, а не какой-либо сигнал.

Есть ли что-нибудь подобное в Java?

1 Ответ

0 голосов
/ 02 ноября 2018

Если у вас есть цикл событий, вы можете запустить фоновый поток, чтобы добавить события в этот цикл событий.

, например

ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // capture errors as well.
Process process = pb.start();
BufferedReader in = new BufferedReader(
        new InputStreamReader(process.getInputStream()));
Thread t = new Thread(() -> {
    try {
        for (String line; (line = in.readLine()) != null; ) {
            Activity.runOnUiThread(() -> useText(line));
        }
    } catch (Exception e) {
        logger.log(e);
    } finally {
        Activity.runOnUiThread(() -> noMoreText());
    }
});
t.setDaemon(true);
t.start();

Вы можете иметь поток, который делает только queue.add(in.readLine()), тогда ваш основной поток может опрашивать эту очередь. Таким образом, все проблемы с многопоточностью просты и содержатся.

static final String EOF = new String(); // use for == comparison later

ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // capture errors as well.
Process process = pb.start();
BufferedReader in = new BufferedReader(
        new InputStreamReader(process.getInputStream()));
int capacity = 1024;
BlockingQueue<String> lines = new ArrayBlockingQueue<>(capacity);
Thread t = new Thread(() -> {
    try {
        for (String line; (line = in.readLine()) != null; ) {
            lines.add(line);
            while (lines.remainingCapacity() < 2) // don't run out of memory if too much.
                Thread.sleep(50);
        }
    } catch (Exception e) {
        logger.log(e);
    } finally {
        lines.offer(EOF);
    }
});
t.setDaemon(true);
t.start();

// later in a loop
String line = lines.poll();
if (line == null) // no data yet.

else if (line == EOF) // we have the EOF marker.
...