Running a Program and Capturing Its Output

Problem

You want to run a program but also capture its output.

Solution

Use the Process object’s getInputStream( ) ; read and copy the contents to System.out or wherever you want them.

Discussion

A program’s standard and error output does not automatically appear anywhere. Arguably, there should be an automatic way to make this happen. But for now, you need to add a few lines of code to grab the program’s output and print it:

// part of ExecDemoLs.java        
p = Runtime.getRuntime(  ).exec(PROGRAM);
 
// getInputStream gives an Input stream connected to
// the process p's standard output (and vice versa). We use
// that to construct a BufferedReader so we can readLine(  ) it.
BufferedReader is = 
    new BufferedReader(new InputStreamReader(p.getInputStream(  )));
 
while ((line = is.readLine(  )) != null)
    System.out.println(line);

This is such a common occurrence that I’ve packaged it up into a class called ExecAndPrint, part of my package com.darwinsys.util . ExecAndPrint has several overloaded forms of its run( ) method (see the documentation for details), but they all take at least a command, and optionally an output file to which the command’s output is written. Example 26-2 shows the code for some of these methods.

Example 26-2. ExecAndPrint.java (partial listing)

/** Need a Runtime object for any of these methods */
protected static Runtime r = Runtime.getRuntime(  );

/** Run the command given as a String, printing its output to System.out */
public static int run(String cmd) throws IOException { 
    return run(cmd, new OutputStreamWriter(System.out));
}

/** Run the command given as a String, print its output to "out" */
public static int run(String cmd, Writer out) throws IOException { 

    String line;
    
    Process p = r.exec(cmd);

    FileIO.copyFile(new InputStreamReader(p.getInputStream(  )), out, true);
    try {
        p.waitFor(  );    // wait for process to complete
    } catch (InterruptedException e) {
        return -1;
    }
    return p.exitValue(  );
}

As a simple example of using exec( ) directly along with ExecAndPrint, I’ll create three temporary files, list them (directory listing), and then delete them. When I run the ExecDemoFiles program, it lists the three files it has created:

-rw-------  1 ian  wheel  0 Jan 29 14:29 file1
-rw-------  1 ian  wheel  0 Jan 29 14:29 file2
-rw-------  1 ian  wheel  0 Jan 29 14:29 file3

Its source code is in Example 26-3.

Example 26-3. ExecDemoFiles.java

// Get and save the Runtime object.
Runtime rt = Runtime.getRuntime(  );

// Create three temporary files
rt.exec("mktemp file1");
rt.exec("mktemp file2");
rt.exec("mktemp file3"); 

// Run the "ls" (directory lister) program
// with its output printed back to us.
String[] args = { "ls", "-l", "file1", "file2", "file3" };
ExecAndPrint.run(args);

rt.exec("rm file1 file2 file3");

A process isn’t necessarily destroyed when the Java program that created it exits or bombs out. Simple text-based programs will be, but window-based programs like kwrite, Netscape, or even a Java-based JFrame application will not. For example, our ExecDemoNS program started Netscape, and when the Exit button is pressed, ExecDemoNS exits but Netscape stays running. What if you want to be sure a process has completed? The Process object has a waitFor( ) method that lets you do so, and an exitValue( ) that tells you the “return code” from the process. Finally, should you wish to forcibly terminate the other process, you can do so with the Process object’s destroy( ) method, which takes no argument and returns no value. Example 26-4 is ExecDemoWait , a program that runs whatever program you name on the command line (along with arguments), captures the program’s standard output, and waits for the program to terminate.

Example 26-4. ExecDemoWait.java

// A Runtime object has methods for dealing with the OS
Runtime r = Runtime.getRuntime(  );
Process p;             // Process tracks one external native process
BufferedReader is;    // reader for output of process
String line;

// Our argv[0] contains the program to run; remaining elements
// of argv contain args for the target program. This is just
// what is needed for the String[] form of exec.
p = r.exec(argv);

System.out.println("In Main after exec");

// getInputStream gives an Input stream connected to 
// the process p's standard output. Just use it to make
// a BufferedReader to readLine(  ) what the program writes out.
is = new BufferedReader(new InputStreamReader(p.getInputStream(  )));

while ((line = is.readLine(  )) != null)
    System.out.println(line);

System.out.println("In Main after EOF");
try {
    p.waitFor(  );    // wait for process to complete
} catch (InterruptedException e) {
    return;
}
System.err.println("Process done, exit status was " + p.exitValue(  ));
return;

See Also

You wouldn’t normally use any form of exec( ) to run one Java program from another in this way; instead, you’d probably create it as a thread within the same process, as this is generally quite a bit faster (the Java interpreter is already up and running, so why wait for another copy of it to start up?). See Chapter 24.

There isn’t anything special to say about running Perl scripts, per se. However, two free packages -- perljvm and PerlCaffeine -- allow you to compile Perl source into Java bytecode. This code can then be interpreted at full speed by any JVM interpreter or Java runtime. If you are a Perl user, you can probably find these modules on CPAN, the Comprehensive Perl Archive Network.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.249.42