在Java中调用CMD命令是一种常见的需求,尤其在需要执行系统级操作(如文件处理、服务启停或调用外部程序)时,Java通过Runtime.exec()
和ProcessBuilder
类提供此功能,以下是详细实现方法和注意事项:
try { // 执行单条命令 Process process = Runtime.getRuntime().exec("cmd /c dir C:\\"); // 读取命令输出 BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK") // Windows中文环境用GBK编码 ); 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
表示执行命令后关闭CMD窗口。waitFor()
确保命令执行完成再继续后续代码。- 必须处理输入流(
getInputStream()
),否则可能阻塞进程。
使用 ProcessBuilder
(推荐)
try { // 支持复杂命令(参数分隔更安全) ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "ping", "www.baidu.com"); builder.redirectErrorStream(true); // 合并错误流到输入流 Process process = builder.start(); // 读取输出 try (Scanner scanner = new Scanner(process.getInputStream(), "GBK")) { while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } } int exitCode = process.waitFor(); System.out.println("Exit Code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
- 优势:
- 避免命令注入风险(参数自动分隔)。
- 支持重定向输入/输出流、设置工作目录等。
redirectErrorStream(true)
简化错误处理。
关键注意事项
-
命令路径处理
- 路径含空格时需拆分参数:
// 错误写法:exec("notepad C:\\My Documents\\test.txt") ProcessBuilder builder = new ProcessBuilder("notepad", "C:\\My Documents\\test.txt");
- 路径含空格时需拆分参数:
-
流处理
- 必须读取输入流和错误流,否则进程可能阻塞,使用多线程处理:
new Thread(() -> { try (BufferedReader errorReader = new BufferedReader( new InputStreamReader(process.getErrorStream())) ) { String line; while ((line = errorReader.readLine()) != null) { System.out.println("[ERROR] " + line); } } catch (IOException e) { e.printStackTrace(); } }).start();
- 必须读取输入流和错误流,否则进程可能阻塞,使用多线程处理:
-
编码问题
- Windows中文环境默认使用
GBK
编码,而非UTF-8:new InputStreamReader(process.getInputStream(), "GBK");
- Windows中文环境默认使用
-
超时控制
- 避免无限等待:
if (!process.waitFor(30, TimeUnit.SECONDS)) { process.destroy(); // 超时终止进程 }
- 避免无限等待:
安全警告
- 命令注入风险:禁止直接拼接用户输入到命令中!
// 危险示例(用户输入fileName="test.txt & del /f /q C:\\") String cmd = "notepad " + userInput; Runtime.getRuntime().exec(cmd);
解决方案:使用
ProcessBuilder
拆分参数,或对输入做严格校验。
典型应用场景
- 调用系统工具(如Ping、Tracert):
ProcessBuilder builder = new ProcessBuilder("ping", "192.168.1.1");
- 执行批处理脚本:
Process process = Runtime.getRuntime().exec("cmd /c start C:\\script.bat");
- 压缩/解压文件(调用7-Zip等外部程序)。
- 简单命令用
Runtime.exec()
,复杂场景用ProcessBuilder
。 - 必须处理流、等待进程结束、注意编码和路径空格。
- 优先使用Java内置API(如文件操作),避免不必要的CMD调用。
引用说明: 参考Oracle官方文档 ProcessBuilder 和 Runtime.exec(),并结合了Java安全编程最佳实践。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/8801.html