Java如何使用ProcessBuilder将进程实时输出打印到控制台?
问题根因
- 调用
cmd.exe时未指定/c参数,命令无法正常执行,触发进程输出流阻塞 - 串行读取标准输出流和错误流的逻辑存在缺陷:若其中一个流的缓冲区被数据填满,目标进程会进入阻塞状态,直到对应流被读取。单线程串行读取的逻辑下会一直等待第一个流读完,因此只能等到进程完全结束后才能拿到全部输出
- 未指定Windows控制台编码,容易出现乱码,也可能干扰流读取逻辑
修复方案
- 为
cmd.exe添加/c执行参数,确保tracert命令可以正常被执行,执行完成后自动退出cmd进程 - 启动两个独立线程分别读取标准输出流和错误流,避免单线程串行读取导致的阻塞问题
- 显式指定输入流编码为GBK,适配Windows控制台默认编码,避免乱码
修复后代码示例
import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.Charset; public class RealTimeTracert { public static void main(String[] args) throws Exception { // 替换为实际需要追踪的目标IP String targetIp = "114.114.114.114"; ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "tracert " + targetIp); Process tracertProcess = processBuilder.start(); // 独立线程处理标准输出流 new Thread(() -> { try (BufferedReader stdReader = new BufferedReader( new InputStreamReader(tracertProcess.getInputStream(), Charset.forName("GBK")))) { String line; while ((line = stdReader.readLine()) != null) { System.out.println("lines:" + line); } } catch (Exception e) { e.printStackTrace(); } }).start(); // 独立线程处理错误输出流 new Thread(() -> { try (BufferedReader errReader = new BufferedReader( new InputStreamReader(tracertProcess.getErrorStream(), Charset.forName("GBK")))) { String line; while ((line = errReader.readLine()) != null) { System.out.println("error lines:" + line); } } catch (Exception e) { e.printStackTrace(); } }).start(); // 阻塞等待tracert进程执行完成 tracertProcess.waitFor(); System.out.println("路由追踪执行结束"); } }
内容的提问来源于stack exchange,提问作者Venkata Narayana Gorusetty
相关产品推荐
相关产品推荐

