16

我正在执行一个返回文件修订号的命令;'文件名'。但是如果执行命令时出现问题,那么应用程序就会挂起。我能做些什么来避免这种情况?请在下面找到我的代码。

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();  
 }
4

2 回答 2

36

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.

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();
}
于 2012-10-22T09:52:55.350 回答
9

此代码基于相同的想法 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());
}

您可以像这样调用该方法

getOutputFromProgram("cmd /C si viewhistory --fields=revision --project="+fileName);

请注意,如果您正在调用的程序挂起,则此方法将挂起,如果需要输入,则会发生这种情况。

于 2014-08-08T12:15:19.720 回答