Runtime.getRuntime().exec()
或ProcessBuilder
类执行CMD命令,通过创建Process对象获取输入/输出流,可读取命令结果并处理执行状态,需注意异常处理和资源释放。核心方法:Runtime.exec()
Runtime.getRuntime().exec()
是Java早期提供的API,适用于简单命令调用。
基础示例
try { // 执行dir命令(Windows)或ls命令(Linux/Mac) Process process = Runtime.getRuntime().exec("cmd /c dir C:\"); // 获取命令输出流 BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream()) ); // 读取输出内容 String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 等待命令执行完成(阻塞当前线程) int exitCode = process.waitFor(); System.out.println("Exit Code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
关键参数说明
cmd /c [命令]
:Windows中/c
表示执行后关闭cmd窗口。- 若命令含空格(如路径),需用数组传参避免解析错误:
Process process = Runtime.getRuntime().exec( new String[]{"cmd", "/c", "echo", "Hello World!"} );
推荐方法:ProcessBuilder
ProcessBuilder
(Java 5+)提供更灵活的参数控制、环境变量管理和流重定向。
基础示例
try { // 构建命令及参数 ProcessBuilder builder = new ProcessBuilder( "cmd.exe", "/c", "ping", "www.baidu.com" ); // 重定向错误流到标准输出(便于统一处理) builder.redirectErrorStream(true); // 启动进程 Process process = builder.start(); // 读取输出 try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream()) )) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } // 检查执行结果 int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("命令执行成功!"); } else { System.out.println("命令执行失败!Exit Code: " + exitCode); } } catch (IOException | InterruptedException e) { e.printStackTrace(); }
进阶功能
- 设置工作目录:
builder.directory(new File("D:\project"));
- 环境变量管理:
Map<String, String> env = builder.environment(); env.put("JAVA_HOME", "C:\Program Files\Java\jdk-17");
- 输出重定向到文件:
builder.redirectOutput(new File("output.log"));
注意事项与最佳实践
-
流处理必须完整
未读取的输出流可能导致进程阻塞,始终处理getInputStream()
(标准输出)和getErrorStream()
(错误输出)。 -
超时控制
使用waitFor(long timeout, TimeUnit unit)
避免无限等待:if (!process.waitFor(30, TimeUnit.SECONDS)) { process.destroy(); // 强制终止进程 }
-
命令注入风险
禁止直接拼接用户输入到命令中!应使用参数化传递:// 错误示例(高危!) String userInput = "malicious_command & rm -rf /"; Runtime.getRuntime().exec("cmd /c " + userInput); // 正确做法 ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "safe-command", userInput);
-
跨平台兼容性
- Windows:命令前缀
cmd /c
- Linux/Mac:使用
/bin/sh -c
或直接调用可执行文件String command = System.getProperty("os.name").toLowerCase().contains("win") ? "cmd /c dir" : "/bin/ls";
- Windows:命令前缀
-
异常处理
捕获IOException
(命令不存在)和InterruptedException
(进程中断)。
Runtime与ProcessBuilder对比
特性 | Runtime.exec() | ProcessBuilder |
---|---|---|
参数灵活性 | 需手动处理空格和引号 | 支持参数列表(更安全) |
环境变量控制 | 无直接支持 | 可通过environment() 修改 |
工作目录设置 | 不支持 | 支持directory() |
流重定向 | 需手动编码 | 内置redirectOutput() |
适用场景 | 简单命令 | 复杂流程或生产环境 |
- 简单命令:优先使用
Runtime.exec()
,注意参数格式。 - 复杂任务:选择
ProcessBuilder
,尤其在需要环境控制、目录设置或流重定向时。 - 安全第一:严格校验外部输入,避免命令注入漏洞。
通过合理选择API并遵循最佳实践,Java可高效安全地集成系统命令,适用于自动化部署、批处理等场景。
引用说明 参考Oracle官方文档:
- Runtime.exec()
- ProcessBuilder
安全实践依据OWASP命令注入防护指南。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/23101.html