Forráskód Böngészése

示例二:获取子进程的标准输入/标准输出/标准错误

yangyi 1 hete
szülő
commit
c29463f564
1 módosított fájl, 67 hozzáadás és 0 törlés
  1. 67 0
      src/main/java/space/anyi/process/ProcessIOExample.java

+ 67 - 0
src/main/java/space/anyi/process/ProcessIOExample.java

@@ -0,0 +1,67 @@
+package space.anyi.process;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 示例二:获取子进程的标准输入 / 标准输出 / 标准错误。
+ *
+ * 子进程为 src/main/resources/code/io/Main.java:
+ * - 从标准输入逐行读取并回显到标准输出;
+ * - 读到 EOF 后向标准错误打印统计信息。
+ * 主进程演示三件事:写入标准输入、读取标准输出、读取标准错误。
+ */
+public class ProcessIOExample {
+    private static final Logger log = LoggerFactory.getLogger(ProcessIOExample.class);
+
+    public static void main(String[] args) throws IOException, InterruptedException {
+        File workDir = Paths.get(System.getProperty("user.dir"), "src", "main", "resources", "code", "io").toFile();
+        Jdk.compileFixture(workDir);
+
+        // 启动子进程(不调用 redirectErrorStream,三条流保持独立)
+        Process process = new ProcessBuilder(Jdk.java(), "-Dfile.encoding=UTF-8", "Main")
+                .directory(workDir)
+                .start();
+
+        // 标准输出、标准错误分别在后台线程读取:
+        // 1) 避免阻塞当前线程;2) 防止子进程输出超过管道缓冲区(约 64KB)时写阻塞、无法退出
+        Thread stdoutDrain = drain("stdout", process.getInputStream());
+        Thread stderrDrain = drain("stderr", process.getErrorStream());
+
+        // 向子进程标准输入写入数据;try-with-resources 关闭输入流即表示 EOF(没有更多输入)
+        try (OutputStream stdin = process.getOutputStream()) {
+            stdin.write("第一行输入\r\n".getBytes(StandardCharsets.UTF_8));
+            stdin.write("第二行输入\r\n".getBytes(StandardCharsets.UTF_8));
+        }
+
+        // 后台读取线程在子进程写满/结束后读到 EOF 才结束,join 后子进程必然已经退出
+        stdoutDrain.join();
+        stderrDrain.join();
+
+        boolean exited = process.waitFor(5, TimeUnit.SECONDS);
+        log.info("子进程是否已退出: {}", exited);
+        log.info("子进程退出状态码: {}", process.exitValue());
+    }
+
+    /** 起一个后台线程把给定输入流按行读取并打日志,读到 EOF(子进程退出)后结束 */
+    private static Thread drain(String tag, InputStream in) {
+        Thread thread = new Thread(
+                () -> new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
+                        .lines()
+                        .forEach(line -> log.info("[{}] {}", tag, line)),
+                "drain-" + tag);
+        thread.setDaemon(true);
+        thread.start();
+        return thread;
+    }
+}