Java Процесс сборки труб вручную - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь вручную передать ввод-вывод между двумя процессами, и я не могу получить какой-либо вывод. Я включил функцию. Я тестировал команду "dir | grep". Cmd1 и Cmd2 - команды по обе стороны от | и я на windows OS. Если команда заканчивается на &, то команда не должна ждать выполнения другого.

 private void pipe(String Cmd1, String Cmd2, String[] baseCommand1)
    {
        if(System.getProperty("os.name").toLowerCase().startsWith("windows"))
        {
            if(System.getProperty("os.name").toLowerCase().startsWith("windows"))
            {
                baseCommand1[0] = "cmd.exe";
                baseCommand1[1] = "/c";
            }
            else
            {
                baseCommand1[0] = "sh";
                baseCommand1[1] = "-c";
            }
        }

        try {
            String[] p1Cmd = { baseCommand1[0], baseCommand1[1], Cmd1 };
            String[] p2Cmd = { baseCommand1[0], baseCommand1[1], Cmd2 };

            ProcessBuilder pb1 = new ProcessBuilder(p1Cmd);
            ProcessBuilder pb2 = new ProcessBuilder(p2Cmd);          
            pb1.redirectInput(ProcessBuilder.Redirect.INHERIT);
            pb1.redirectOutput(pb2.redirectInput());
            pb2.redirectOutput(ProcessBuilder.Redirect.INHERIT);


            Process p1 = pb1.start();
            Process p2 = pb2.start();

            java.io.InputStream in = p1.getInputStream();
            java.io.OutputStream out = p2.getOutputStream();

            int c;
            while ((c = in.read()) != -1) {
                System.out.println(c);
                    out.write(c);
            }

            out.flush();
            out.close();


            if(!Cmd2.contains("&"))
            {
                p1.waitFor();
                p2.waitFor();
            }

        }
        catch (Exception ex) {
            System.out.print(ex);
        }
    }




1 Ответ

0 голосов
/ 02 мая 2020

Ваш подпроцесс записывает много данных? Общая проблема с использованием класса Process через Runtime.exe c или ProcessBuilder заключается в том, что вы можете заблокировать приложение Java, если не используете большие стандартные выходные потоки (или сообщения об ошибках), сгенерированные подпроцессом.

Например, попробуйте это в jshell - он не будет выполняться на моей Windows 10 машине, потому что поток STDOUT не используется (и C: \ Temp большой)

var p = Runtime.getRuntime().exec("cmd.exe /c \"dir /s C:\\Temp \"")
p.waitFor()
// DOES NOT END...

ОДНАКО: если я добавляю поток для использования большого STDOUT того же процесса, все в порядке и работает быстро:

var p = Runtime.getRuntime().exec("cmd.exe /c \"dir /s C:\\Temp \"")
var buf = new ByteArrayOutputStream(8192);
var stream = p.getInputStream();
Runnable r = () -> {
    byte [] buffer = new byte[1024];
    System.out.println("run() START");
    try {
        int len;
        while ((len = stream.read(buffer)) != -1)
            buf.write(buffer, 0, len);
        stream.close();
    }
    catch (IOException ex) {
        throw new UncheckedIOException(ex);
    }
    finally {
        System.out.println("run() END");
    }
}

new Thread(r).start();
p.waitFor()

System.out.println("Your process returned: "+new String(buf.toByteArray()) );

Может случиться так, что ваш cmd | cmd генерирует длинный поток, и вам нужен поток службы для использования вывод до waitFor ()

...