核心方法
Java提供两种主要方式调用exe并传递参数:
Runtime.getRuntime().exec()(传统方法)ProcessBuilder(推荐,更灵活安全)
参数添加的正确方式
方法1:使用 Runtime.exec()
try {
// 直接传递命令和参数数组
String[] cmdArray = {"C:\\Program.exe", "-arg1", "value with space", "--flag"};
Process process = Runtime.getRuntime().exec(cmdArray);
// 等待执行完成并获取返回值
int exitCode = process.waitFor();
System.out.println("Exit Code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
关键点:
- 参数按顺序放入数组,避免手动拼接字符串。
- 路径或含空格的参数无需额外引号,Java会自动处理。
方法2:使用 ProcessBuilder (推荐)
try {
ProcessBuilder pb = new ProcessBuilder(
"D:\\app\\tool.exe", // exe路径
"-input", "data.txt", // 参数1
"-o", "output", // 参数2
"--verbose" // 标志参数
);
// 设置工作目录(可选)
pb.directory(new File("C:\\workdir"));
// 启动进程并等待
Process process = pb.start();
int exitCode = process.waitFor();
// 获取输出流内容(重要!避免阻塞)
InputStream inputStream = process.getInputStream();
String output = new String(inputStream.readAllBytes());
System.out.println("Output: " + output);
} catch (Exception e) {
e.printStackTrace();
}
优势:
- 支持设置工作目录、环境变量。
- 自动处理参数转义,降低错误风险。
- 提供重定向输入/输出流的控制。
参数处理规则与陷阱
-
空格和特殊字符
- 错误方式:
exec("C:\\test.exe -arg 'file with space.txt'")(引号不会被正确解析)。 - 正确方式:将含空格的参数作为数组独立元素,如
{"-arg", "file with space.txt"}。
- 错误方式:
-
路径规范
- 使用双反斜杠或正斜杠:
"C:/app/program.exe"或"C:\\\\app\\\\program.exe"。
- 使用双反斜杠或正斜杠:
-
参数类型示例
| 参数类型 | 正确写法 |
|—————-|—————————–|
| 普通参数 |"-mode","fast"|
| 布尔标志 |"--enable-log"|
| 带空格的路径 |"C:\\My Files\\data.txt"|
| 键值对 |"-config","app.cfg"|
常见问题解决方案
-
程序无响应或阻塞
- 必须读取进程的输出流和错误流(通过
process.getInputStream()和process.getErrorStream()),否则缓冲区满会导致死锁。 - 使用线程异步读取流,或调用
process.waitFor()前清空缓冲区。
- 必须读取进程的输出流和错误流(通过
-
权限问题
- 若需管理员权限,需通过脚本启动(如Windows的
runas命令),Java本身无法提权。
- 若需管理员权限,需通过脚本启动(如Windows的
-
中文乱码
指定流编码:BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), "GBK") // Windows中文环境 ); -
超时控制
使用process.waitFor(long timeout, TimeUnit unit):if (!process.waitFor(30, TimeUnit.SECONDS)) { process.destroy(); // 强制终止 }
安全注意事项
-
禁止拼接用户输入:
若参数包含用户输入(如表单数据),必须严格验证,防止命令注入攻击:// 危险示例!可能被注入恶意命令 String userInput = request.getParameter("data"); Runtime.getRuntime().exec("cmd.exe /C tool.exe " + userInput); // 安全做法:使用参数数组 String[] safeCmd = {"tool.exe", sanitize(userInput)}; // sanitize()过滤特殊字符 -
使用白名单验证输入内容,或转义、
&、等Shell元字符。
完整示例:调用7-Zip压缩文件
try {
ProcessBuilder pb = new ProcessBuilder(
"C:\\Program Files\\7-Zip\\7z.exe",
"a", // 添加压缩
"-t7z", // 压缩类型
"archive.7z", // 输出文件
"D:\\docs\\report.pdf", // 被压缩文件
"-pMyPassword" // 密码参数
);
// 重定向错误流到控制台
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Process process = pb.start();
// 读取输出
String result = new String(process.getInputStream().readAllBytes());
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("压缩成功!输出: " + result);
} else {
System.out.println("错误码: " + exitCode);
}
} catch (Exception e) {
e.printStackTrace();
}
- 优先使用
ProcessBuilder:更安全、功能更完善。 - 参数独立为数组元素:避免手动处理空格和引号。
- 务必处理输入/输出流:防止进程阻塞。
- 严格验证外部输入:防范命令注入风险。
通过遵循这些实践,可确保Java调用exe的稳定性和安全性,适用于自动化脚本、系统集成等复杂场景。
引用说明基于Oracle官方文档《ProcessBuilder》和《Runtime.exec()》的技术规范,并结合常见安全实践编写。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/4748.html