Fetch and store output from a subprocess in Java

2020-06-26 18:45发布

问题:

I'm working on something that requires me to start to subprocess(command prompt) and execute some commands on it. I need to fetch the output from the subprocess and store it in a file or String. here's what I have done so far, and it doesn't work:

public static void main(String args[])
{
        try
    {
        Runtime RT = Runtime.getRuntime();
        String command = "cmd /c start javap java.lang.String"; 
        File file = new File("write.txt");
        Writer output = new BufferedWriter(new FileWriter(file));
            BufferedReader br = new(BufferedReader(newInputStreamReader(RT.exec(command).getInputStream()));
        String temp = br.readLine();
        while(!temp.equals(null))
        {
            output.write(temp);
            temp = br.readLine();
        }
        output.close();
        RT.exec("exit");
    }
    catch(Exception e)
    {
        System.out.println(e);
    }
}

回答1:

Start changing this:

new(BufferedReader(newInputStreamReader(

To:

new BufferedReader(new InputStreamReader(

Compile and see if you still have the problem

edit

Also, there is a good reason why you shouldn't catch Exception, you also catch programming errors like a NullPointerException

 while( !temp.equals(null)) { //Throws NullPointerExceptin when temp is null

Change it with:

 while( temp != null ) { //!temp.equals(null)) {

Finally you don't have to "exit" since you're not inside the cmd really.

Corrected version

This version runs as you intend:

import java.io.*;
class Rt { 
  public static void main(String args[]) throws Exception {
          Runtime RT = Runtime.getRuntime();
          String  command =  "javap java.lang.String" ; 
          File file = new File("write.txt");
          Writer output = new BufferedWriter(new FileWriter(file));
          BufferedReader br = new BufferedReader(new InputStreamReader(RT.exec(command).getInputStream()));
          String temp = br.readLine();
          while( temp != null ) { //!temp.equals(null)) {
              output.write(temp);
              temp = br.readLine();
          }
          output.close();
          //RT.exec("exit");
  }
}

edit Final remarks:

Since Java 1.5 the preferred way to invoke a command is using ProcessBuilder and it is better if you use an array of strings instead of a single string ( or varargs ).

When you're building your output you can get rid of the file object and pass the file name directly to the filewriter.

While reading the line you can assign and evaluate in the condition.

Java's coding conventions suggest to use the opening brace in the same like.

This would be my version of your code:

class Rt { 
   public static void main(String args[]) throws Exception {

      Writer output     = new BufferedWriter(new FileWriter ( "write.txt"));
      InputStream in    = new ProcessBuilder("javap", "java.lang.String").start().getInputStream();
      BufferedReader br = new BufferedReader( new InputStreamReader(in)); 
      String line = null;
      while( ( line = br.readLine() )   != null ) {
          output.write( line );
      }
      output.close();
  }
}

It might need still some work, but I hope it helps you.



回答2:

Here is an example which should work:

        StringBuffer outStream = new StringBuffer();
        StringBuffer errStream = new StringBuffer();
        Runtime runtime = Runtime.getRuntime();

        Process process = null;
        try {
            process = runtime.exec(command);
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }

        InputStream outIs = process.getInputStream();
        MonitorOutputThread sout = new MonitorOutputThread(outIs, outStream);
        sout.run();

        InputStream errIs = process.getErrorStream();
        MonitorOutputThread serr = new MonitorOutputThread(errIs, errStream);
        serr.run();

        while (sout.isAlive() || serr.isAlive()) {
            try {
                sleep(100);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
                // ignore
            }
        }

And the code for MonitorOutputThread

private class MonitorOutputThread extends Thread {

    private final InputStream is;
    private final StringBuffer output;

    public MonitorOutputThread(InputStream is, StringBuffer output) {
        this.is = is;
        this.output = output;
    }

    @Override
    public void run() {
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);

        String line = null;
        try {
            while ((line = br.readLine()) != null) {
                output.append(line);
                output.append(LINE_SEPARATOR);
            }

            if (output.length() >= 1) {
                char lastChar = output.charAt(output.length() - 1);

                if (lastChar == '\n') {
                    output.deleteCharAt(output.length() - 1);
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
    }

}

This should catch both the standard output and standard error of the command.



回答3:

DevDaily has a simple example of how to work with Process class.
See the snippet:

import java.io.*;

public class JavaRunCommand {

    public static void main(String args[]) {
        String s = null;

        try {

            // run the Unix "ps -ef" command
            // using the Runtime exec method:
            Process p = Runtime.getRuntime().exec("ps -ef");

            BufferedReader stdInput = new BufferedReader(new 
                 InputStreamReader(p.getInputStream()));

            BufferedReader stdError = new BufferedReader(new 
                 InputStreamReader(p.getErrorStream()));

            // read the output from the command
            System.out.println("Here is the standard output of the command:\n");
            while ((s = stdInput.readLine()) != null) {
                System.out.println(s);
            }

            // read any errors from the attempted command
            System.out.println("Here is the standard error of the command (if any):\n");
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }

            System.exit(0);
        }
        catch (IOException e) {
            System.out.println("exception happened - here's what I know: ");
            e.printStackTrace();
            System.exit(-1);
        }
    }
}

or even check this code I've writen some time ago