在进行开发的时候, 我们有时候需要通过命令来执行别的程序,并获取返回结果。
public static void main(String[] args) throws Exception{
String cmd = "ls";
Process ps = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
String stdout = new String(readAll(ps.getInputStream()));
String stderr = new String(readAll(ps.getErrorStream()));
ps.waitFor();
System.out.println("stdout is :" + stdout);
System.out.println("stderr is :" + stderr);
System.out.println("exit code is :" + exitCode);
}
static byte[] readAll(InputStream is) throws Exception{
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int n;
while (( n = is.read(bytes)) != -1) {
os.write(bytes, 0, n);
}
return os.toByteArray();
}
但是在实际使用过程中有时会出现问题, 调用命令启动的子进程会卡住,永远得不到返回。
原因是: 子进程和父进程之间建立管道连接, 子进程的错误输出和标准输出会向两个不同的管道进行写入,而管道的缓冲区有大小限制,当子进程执行过程中错误输出过多,并且没有标准输出时。 java进程的读标准输出时会block住,而子进程把管道缓冲区打满,子进程也会block住,这样就会产生死锁。
解决方案: 启动两个线程来读取输出
public static void main(String[] args) throws Exception{
String cmd = "ls";
Process ps = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
Future<String> stdoutFuture =
Executors.newSingleThreadExecutor().submit(() -> new String(readAll(ps.getInputStream())));
Future<String> stderrFuture =
Executors.newSingleThreadExecutor().submit(() -> new String(readAll(ps.getErrorStream())));
int exitCode = ps.waitFor();
System.out.println("stdout is :" + stdoutFuture.get());
System.out.println("stderr is :" + stderrFuture.get());
System.out.println("exit code is :" + exitCode);
}
static byte[] readAll(InputStream is) throws Exception{
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int n;
while (( n = is.read(bytes)) != -1) {
os.write(bytes, 0, n);
}
return os.toByteArray();
}
网友评论