我正在尝试使用 ProcessBuilder 执行批处理脚本,但不明白为什么它不起作用。
我构建了一个小型 PoC 来展示我的问题,为了使其正常工作,您需要在 C 驱动器上创建一些文件夹:
22840c1a
22840c1a\子文件夹
然后将 calc.exe 复制到子文件夹中。接下来在 22840c1a 内创建 start.bat。将以下内容粘贴到start.bat中
@echo off
echo "Set WorkingDirectory"
cd /d C:\22840c1a\subfolder
echo "Start"
C:\22840c1a\subfolder\calc.exe
这样您就可以运行以下单元测试并重现问题:
更新:添加了工作 PoC
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
class BatchExecutionTest {
@Test
void pocWorking() {
execute(Arrays.asList("C:\\22840c1a\\start.bat"), "C:\\22840c1a");
}
@Test
void pocNotWorking() {
execute(Arrays.asList("start.bat"), "C:\\22840c1a");
}
@Test
void pocWorkingCmd1() {
execute(Arrays.asList("cmd", "/c", "C:\\22840c1a\\start.bat"), "C:\\22840c1a");
}
@Test
void pocWorkingCmd2() {
execute(Arrays.asList("cmd", "/c", "start.bat"), "C:\\22840c1a");
}
public static void execute(List<String> commands, String workingDirectory) {
try {
final ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
pb.directory(new File(workingDirectory));
pb.start();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
如果一切按预期工作,单元测试将无法执行 start.bat,因为找不到文件。但是,您可以从 cmd 运行 start.bat 并且它工作正常。为什么 ProcessBuilder 无法执行批处理脚本?
您需要将可执行文件传递给
ProcessBuilder
,而 start.bat
不是 可执行文件。因此,如果您想使用 ProcessBuilder
运行批处理文件,则必须将 cmd.exe
传递给 ProcessBuilder
。
如果您只想提供文件,即
start.bat
,那么您可以使用类java.awt.Desktop
。这是一个简单的例子:
java.awt.Desktop.getDesktop().open(new File("start.bat"));
方法
open
为您想要“打开”的文件以及扩展名为 .bat
(即 cmd.exe
)的文件找到适当的可执行文件。
请注意,上述代码假定支持
Desktop
。你应该首先做:
Desktop.isDesktopSupported()
另请注意,如果您的真正意图只是运行
calc.exe
,则无需将其包装在批处理文件中。将可执行文件的路径直接传递给ProcessBuilder
,即
ProcessBuilder pb = new ProcessBuilder("C:\\22840c1a\\subfolder\\calc.exe");