java Runtime.getRuntime().exec(cmd) 挂起
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13008526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Runtime.getRuntime().exec(cmd) hanging
提问by user1688404
I am executing a command which returns me the Revision number of a file; 'fileName'. But if there is some problem executing the command, then the application hangs up. What can I do to avoid that condition? Please find below my code.
我正在执行一个命令,该命令返回文件的修订号;'文件名'。但是如果在执行命令时出现问题,应用程序就会挂断。我该怎么做才能避免这种情况?请在我的代码下方找到。
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
回答by Arham
I guess the issue is that you are only reading InputStream and not reading ErrorStream. You also have to take care that both the streams are read in parallel. It may so happen that currently the data piped from the output stream fills up the OS buffer, your exec command will be automatically be suspended to give your reader a chance to empty the buffer. But the program will still be waiting for the output to process. Hence, the hang occurs.
我想问题是您只读取 InputStream 而不是读取 ErrorStream。您还必须注意并行读取两个流。有可能当前从输出流通过管道传输的数据填满了操作系统缓冲区,您的 exec 命令将自动挂起,让您的读者有机会清空缓冲区。但程序仍将等待输出处理。因此,挂起发生。
You can create a separate class to handle both the Input and Error Stream as follows,
您可以创建一个单独的类来处理输入和错误流,如下所示,
public class ReadStream implements Runnable {
String name;
InputStream is;
Thread thread;
public ReadStream(String name, InputStream is) {
this.name = name;
this.is = is;
}
public void start () {
thread = new Thread (this);
thread.start ();
}
public void run () {
try {
InputStreamReader isr = new InputStreamReader (is);
BufferedReader br = new BufferedReader (isr);
while (true) {
String s = br.readLine ();
if (s == null) break;
System.out.println ("[" + name + "] " + s);
}
is.close ();
} catch (Exception ex) {
System.out.println ("Problem reading stream " + name + "... :" + ex);
ex.printStackTrace ();
}
}
}
The way you use it is as follows,
你的使用方法如下,
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
s1 = new ReadStream("stdin", p.getInputStream ());
s2 = new ReadStream("stderr", p.getErrorStream ());
s1.start ();
s2.start ();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(p != null)
p.destroy();
}
回答by mikeyreilly
This code is based on the same idea Arham's answer, but is implemented using a java 8 parallel stream, which makes it a little more concise.
此代码基于相同的想法 Arham 的答案,但使用 java 8 并行流实现,这使其更加简洁。
public static String getOutputFromProgram(String program) throws IOException {
Process proc = Runtime.getRuntime().exec(program);
return Stream.of(proc.getErrorStream(), proc.getInputStream()).parallel().map((InputStream isForOutput) -> {
StringBuilder output = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(isForOutput))) {
String line;
while ((line = br.readLine()) != null) {
output.append(line);
output.append("\n");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return output;
}).collect(Collectors.joining());
}
You can call the method like this
你可以像这样调用方法
getOutputFromProgram("cmd /C si viewhistory --fields=revision --project="+fileName);
Note that this method will hang if the program you are calling hangs, which will happen if it requires input.
请注意,如果您正在调用的程序挂起,则此方法将挂起,如果需要输入,则会发生这种情况。