如何优化BufferedReader读取?Java获取安装软件耗时过长问题
解决Java读取外部进程输出耗时过长的问题
你的代码中sb.append(reader.lines().collect(Collectors.joining("\n")))执行后耗时剧增,核心原因是未处理外部进程的错误输出流,导致进程输出缓冲区满后阻塞,进而拖慢Java代码的读取流程;同时Stream API的拼接方式也会带来额外的对象创建开销。
解决步骤
- 合并错误流到输入流:通过
ProcessBuilder.redirectErrorStream(true)把进程的错误输出和标准输出合并,避免因错误流缓冲区满导致进程挂起。 - 替换高效读取方式:用
BufferedReader.readLine()循环拼接,避免Stream API带来的额外开销,减少临时字符串创建。
修改后的代码
class InstalledPrograms { public static String getPrograms() { StringBuilder sb = new StringBuilder(); try { ProcessBuilder processBuilder = new ProcessBuilder(getCommand().split(" ")); // 合并错误流到输入流,避免进程因错误缓冲区满阻塞 processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; // 逐行读取拼接,减少Stream API的额外开销 while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } // 等待进程执行完成,确保输出全部读取 process.waitFor(); } } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } private static String getCommand() { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("window")) return "wmic product get name,version"; if (os.contains("linux")) return "dpkg --list"; return "pkgutil --pkgs"; // for MacOS } }
补充说明
redirectErrorStream(true)是核心修复点:外部进程运行时产生的错误输出如果未被读取,缓冲区满后会导致进程停止输出并等待,这是耗时剧增的主要原因。- 逐行读取比
Stream拼接更高效:直接操作StringBuilder避免了Stream包装、收集等额外操作,减少内存开销。 process.waitFor()确保进程执行完成后再结束读取,避免遗漏部分输出内容。
内容的提问来源于stack exchange,提问作者Fagi
相关产品推荐
相关产品推荐

