核心实现方式
Java通过Runtime
或ProcessBuilder
类执行外部命令,本质都是启动系统进程。
使用 Runtime.exec()
(传统方法)
import java.io.BufferedReader; import java.io.InputStreamReader; public class RunDOSCommand { public static void main(String[] args) { try { // 执行命令 Process process = Runtime.getRuntime().exec("cmd /c dir C:\\"); // 读取命令输出 BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK") // 中文系统需指定编码 ); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 等待命令执行完成 int exitCode = process.waitFor(); System.out.println("Exit Code: " + exitCode); } catch (Exception e) { e.printStackTrace(); } } }
- 关键参数说明:
cmd /c [命令]
:执行后关闭命令行窗口(/c
可替换为/k
保持窗口打开)。- 路径中的空格需用双引号包裹(如
"C:\\Program Files"
)。 - 中文系统必须指定编码(如
GBK
),否则输出乱码。
使用 ProcessBuilder
(推荐方式)
public class ProcessBuilderExample { public static void main(String[] args) { try { // 构建命令及参数 ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "ping", "www.baidu.com"); // 设置工作目录(可选) builder.directory(new File("C:\\")); // 执行并获取输出 Process process = builder.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK") ); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("Exit Code: " + exitCode); } catch (Exception e) { e.printStackTrace(); } } }
- 优势:
- 支持参数列表(避免手动拼接命令)。
- 可设置工作目录、环境变量。
- 更安全的命令解析(降低注入风险)。
关键注意事项
-
命令注入风险
禁止直接拼接用户输入到命令中!// 危险示例!用户输入可能执行恶意命令 String userInput = args[0]; Runtime.getRuntime().exec("cmd /c dir " + userInput); // 若输入"& format C:"将导致灾难
解决方案:使用
ProcessBuilder
拆分参数,或严格校验输入。 -
跨平台兼容性
- Windows命令需以
cmd /c
开头(如cmd /c dir
)。 - Linux/Mac使用
/bin/sh -c
(如/bin/sh -c ls
)。 - 建议通过条件判断系统类型:
String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { builder.command("cmd", "/c", "dir"); } else { builder.command("sh", "-c", "ls"); }
- Windows命令需以
-
处理输出流阻塞
进程的输出流和错误流必须被读取,否则可能导致线程阻塞。
优化方案:开独立线程消费流:Thread outputThread = new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK"))) { String line; while ((line = reader.readLine()) != null) { System.out.println("OUT: " + line); } } catch (IOException e) { e.printStackTrace(); } }); outputThread.start();
-
超时控制
避免长时间阻塞:if (!process.waitFor(30, TimeUnit.SECONDS)) { // 设置30秒超时 process.destroy(); // 终止进程 throw new RuntimeException("Command timed out"); }
常见应用场景
- 文件操作
// 复制文件 ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "copy", "src.txt", "dest.txt");
- 网络诊断
// Ping测试 ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "ping", "192.168.1.1");
- 启动外部程序
// 打开记事本 Runtime.getRuntime().exec("notepad.exe");
最佳实践总结
- 安全第一:始终校验外部输入,优先用
ProcessBuilder
避免命令注入。 - 编码明确:中文Windows使用
GBK
,Linux/Mac用UTF-8
。 - 资源释放:关闭
InputStream
、OutputStream
防止资源泄漏。 - 错误处理:检查
exitCode
并读取错误流(process.getErrorStream()
)。 - 权限管理:需
Administrator
权限的命令(如关机),需以管理员身份运行Java进程。
引用说明参考Oracle官方文档 ProcessBuilder 和 Runtime.exec() 的实现规范,并结合了Java安全编程实践。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/7408.html