Nat*_*man 5 java windows cmd process batch-file
这必须是我曾经观察过的最奇怪的事情之一.考虑以下Java程序:
import java.io.IOException;
public class StrangeError {
public static void main(String[] args) {
try {
Process process = new ProcessBuilder(
"cmd",
"/c",
"\"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" amd64 && set"
).start();
process.waitFor();
} catch (IOException|InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我编译它javac StrangeError.java,将其复制到运行Windows Server 2012 R2的服务器上,然后运行它java StrangeError.
事情开始变得奇怪了.该程序挂起,等待它产生的过程完成.这不是预期的行为,因为vcvarsall.bat脚本应该立即完成set.
所以我开始玩游戏并发现以下内容:
set原因vcvarsall.bat终止vcvarsall.bat原因set终止&&有||原因的一切正确终止vcvarsall.bat到桌面上的某个位置并更改路径会导致所有内容正确终止vcvarsall.bat从MSVC2013 重现,但也可以在Windows 10上与MSVC2015重现原计划究竟出了什么问题?如果我将整个命令(cmd /c "C:\...)复制并粘贴到Start-> Run中,它会立即启动 cmd并终止,如预期的那样.
这是Java的错误吗?这是Windows的错误吗?
这是Java的错误吗?这是Windows的错误吗?
这是你代码中的一个错误.:-)
默认情况下,使用ProcessBuilder对象创建的子进程将输出重定向到管道,其父结束可以使用获取Process.getInputStream(),如果您的代码没有使用它,则不会自动耗尽.
由于您的代码只是在.waitFor没有任何排除管道的情况下进行调用,因此一旦管道缓冲区溢出,它就会死锁.我相信默认缓冲区大小是4,096字节.在我的机器上,您运行的命令的输出是5,192字节,但这将取决于环境块的原始内容.(从它的声音来看,你的环境中的输出长度是临界的,只是在极限之上,所以即使像改变VS的版本这样的小变化也会有所不同.)
许多可能的解决方案之一,取决于你实际上要做的事情,是告诉Java不管道孩子的输出:
import java.io.IOException;
public class StrangeError {
public static void main(String[] args) {
try {
ProcessBuilder processb = new ProcessBuilder(
"cmd",
"/c",
"\"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" amd64 && set"
);
processb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = processb.start();
process.waitFor();
} catch (IOException|InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |