核心方法
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