我正在尝试编写一个程序,它启动 Windows 控制台 (cmd) 的进程并将输入、输出和错误流重定向到 System.in/out/err。此外,如果进程关闭(通过命令退出),我的程序应该关闭。
我已经写了一个解决方案,这很有效。唯一的问题是我使用的线程没有注意到进程已关闭。另外我不知道为所有这些流编写一个新线程是否是必要的,所以如果你知道一个更简单的解决方案来重定向流,我想听听。
这是我的SSCCE:
public class Main {
public static boolean run = true;
public static void main(String[] args) throws IOException {
ProcessBuilder p = new ProcessBuilder("cmd");
final Process pr = p.start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
pr.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("test");
run = false;
}
});
// read(is);
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (run)
try {
write(System.in, pr.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (run)
try {
write(pr.getInputStream(), System.out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (run)
try {
write(pr.getErrorStream(), System.err);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public static void write(InputStream is, OutputStream os)
throws IOException {
byte[] buf = new byte[1024];
int len = is.read(buf);
if (len != -1) {
byte[] data = new byte[len];
for (int i = 0; i < len; i++) {
data[i] = buf[i];
}
os.write(data);
os.flush();
}
}
}
发生的情况是,我为每个流重定向创建一个新线程,并且重定向本身通过该write(inputStream,outputStream)
方法发生。
但是我用来检查进程是否关闭的线程(pr.waitFor()
)并没有像我想象的那样工作。因此,如果 cmd 关闭,我不会注意到。
编辑2
好的,我只是忘了启动线程。但现在我能够接近这个问题。
System.in 重定向到 process.getOutputStream() 并没有注意到进程将要关闭。那是因为is.read(buf)
是一种阻塞方法。因此,如果我尝试向 Process 写入新命令,那么它会注意到应该关闭流并完成程序。
如果有任何解决方案可以在没有线程的情况下重定向 Streams,我想以这种方式实现它。我认为这会更容易使用。