接受或返回的对象
redirectInput()
resp,
redirectOutput()
描述某项政策;它们不代表实际的通道。
所以根据声明
source.redirectInput(target.redirectInput())
您只是指定两个进程应该具有相同的策略,而不是链接通道。
事实上,在Java8中,直接链接两个进程的通道是不可能的。要达到类似效果,最好启动一个后台线程,该线程将读取第一个进程输出并将其写入第二个进程输入:
static List<Process> doPipeJava8() throws IOException {
Process pSource = new ProcessBuilder("cmd", "/S/D/c", "dir", "/s/b", ".")
.redirectInput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
Process pTarget;
try {
pTarget = new ProcessBuilder("cmd", "/S/D/c", "findstr", "dat$")
.redirectErrorStream(true)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.start();
} catch(Throwable t) {
pSource.destroyForcibly();
throw t;
}
new Thread(() -> {
try(InputStream srcOut = pSource.getInputStream();
OutputStream dstIn = pTarget.getOutputStream()) {
byte[] buffer = new byte[1024];
while(pSource.isAlive() && pTarget.isAlive()) {
int r = srcOut.read(buffer);
if(r > 0) dstIn.write(buffer, 0, r);
}
} catch(IOException ex) {}
}).start();
return Arrays.asList(pSource, pTarget);
}
这将错误通道、第一个进程的输入通道和最后一个进程的输出通道配置为
INHERIT
因此,他们将使用我们的启动过程控制台。第一个过程输出和第二个过程输入保持默认值
PIPE
这意味着建立一个管道
我们的启动过程
,因此我们有责任将数据从一个管道复制到另一个管道。
该方法可用作
List<Process> sub = doPipeJava8();
Process pSource = sub.get(0), pTarget = sub.get(1);
pSource.waitFor();
pTarget.waitFor();
如果我们删除
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
来自
pTarget
过程中,我们可以读取最终输出:
List<Process> sub = doPipeJava8();
Process pSource = sub.get(0), pTarget = sub.get(1);
List<String> result = new BufferedReader(new InputStreamReader(pTarget.getInputStream()))
.lines().collect(Collectors.toList());
Java 9是第一个支持在子进程之间建立管道的Java版本。它将解决方案简化为
static List<Process> doPipeJava9() throws IOException {
return ProcessBuilder.startPipeline(
List.of(new ProcessBuilder("cmd", "/S/D/c", "dir", "/s/b", ".")
.redirectInput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT),
new ProcessBuilder("cmd", "/S/D/c", "findstr", "dat$")
.redirectErrorStream(true)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)) );
}
它与另一个解决方案一样;上面的示例配置为允许第一个进程从控制台读取(如果需要),最后一个进程写入控制台。同样,如果我们省略
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
从最后一个process builder中,我们可以读取最后一个流程输出。
但如果可能,它将使用系统本地管道功能