3

I want to get a process' output (Git.exe to be exact) and convert it to a String object. Previously sometimes my code was blocked. Then I figured out that it's because the process' ErrorStream has some output and I have to manually capture that (which I'm not interested in). I changed my code to this:

public static String runProcess(String executable, String parameter) {
    try {
        String path = String.format("%s %s", executable, parameter);
        Process pr = Runtime.getRuntime().exec(path);

        // ignore errors
        StringWriter errors = new StringWriter();
        IOUtils.copy(pr.getErrorStream(), errors);

        StringWriter writer = new StringWriter();
        IOUtils.copy(pr.getInputStream(), writer);

        pr.waitFor();
        return writer.toString();
    } catch (Exception e) {
        return null;
    }
}

Now it works mostly fine, but then again, sometimes it gets blocked again in this line: IOUtils.copy(pr.getErrorStream(), errors);.

Is there some way I could just get the output from the git.exe without hitting a block? Thanks.

Anderson Pimentel
  • 5,086
  • 2
  • 32
  • 54
Alireza Noori
  • 14,961
  • 30
  • 95
  • 179

2 Answers2

3

Using this beautiful article and the StreamGobbler class described there (which I modified a little) I solved the problem. My implementation of StreamGobbler:

class StreamGobbler extends Thread {
    InputStream is;
    String output;

    StreamGobbler(InputStream is) {
        this.is = is;
    }

    public String getOutput() {
        return output;
    }

    public void run() {
        try {
            StringWriter writer = new StringWriter();
            IOUtils.copy(is, writer);
            output = writer.toString();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

and my function is:

public static String runProcess(String executable, String parameter) {
    try {
        String path = String.format("%s %s", executable, parameter);
        Process pr = Runtime.getRuntime().exec(path);

        StreamGobbler errorGobbler = new StreamGobbler(pr.getErrorStream());
        StreamGobbler outputGobbler = new StreamGobbler(pr.getInputStream());

        // kick them off concurrently
        errorGobbler.start();
        outputGobbler.start();

        pr.waitFor();
        return outputGobbler.getOutput();
    } catch (Exception e) {
        return null;
    }
}
Alireza Noori
  • 14,961
  • 30
  • 95
  • 179
  • 2
    outputGobbler.getOutput() will return null in cases where the streamgobbler threads haven't had a chance to read in the input before the process is finished. – asm Nov 26 '18 at 19:11
0

Use ProcessBuilder or Apache commons-exec.

Your posted code has bugs, this is a hard topic to get right.

krosenvold
  • 75,535
  • 32
  • 152
  • 208