O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


JAVA HACK

Reading stdin and stderr from a Process object
When running a program using Runtime.getRuntime().exec(command) you may find your programming hanging when you try to read from the error or input streams. This hack shows how to get around it.

Contributed by:
Al Sutton
[03/31/04 | Discuss (5) | Link to this hack]

When reading any stream the java methods will block when nothing is available and the stream is left open.

When you have a started a process using Runtime.getRuntime().exec(command) you will may find that if you try to read either the stream returned by getErrorStream or the stream returned by getInputStream your application will hang. This happens when data has been sent to the stream you are not reading and no further input comes on the stream you are reading (e.g. an error message sent to the error stream while you are reading the input stream). As there is data waiting to be read from one of the streams the process will not exit and close the stream you are reading, so your application will hang waiting for data that will never arrive.

The way around this is to create two objects which each run in it's own thread and read one of the streams and then calling the waitFor method of the Process object returned by the Runtime.getRuntime().exec(command) method.

By reading the streams in their own threads neither will block the other, and by using waitFor you ensure all of the available data is available before continuing.

A class which could perform the job of reading each of the streams looks like this;

class InputStreamHandler
 extends Thread
{
 /**
  * Stream being read
  */
		
 private InputStream m_stream;
		
 /**
  * The StringBuffer holding the captured output
  */
		
 private StringBuffer m_captureBuffer;
		
 /**
  * Constructor. 
  * 
  * @param 
  */
		
 InputStreamHandler( StringBuffer captureBuffer, InputStream stream )
 {
  m_stream = stream;
  m_captureBuffer = captureBuffer;
  start();
 }
		
 /**
  * Stream the data.
  */
		
 public void run()
 {
  try
  {
   int nextChar;
   while( (nextChar = m_stream.read()) != -1 )
   {
    m_captureBuffer.append((char)nextChar);
   }
  }
  catch( IOException ioe )
  {
  }
 }
}

When you want to use this you use the following code in your method;

Process application = Runtime.getRuntime().exec(command);

StringBuffer inBuffer = new StringBuffer();
InputStream inStream = application.getInputStream();
new InputStreamHandler( inBuffer, inStream );

StringBuffer errBuffer = new StringBuffer();
InputStream errStream = application.getErrorStream();
new InputStreamHandler( errBuffer , errStream );

application.waitFor();

Once this code finishes the StringBuffer called inBuffer will hold all the data from the input stream, and errBuffer will contain all the data from the error stream.


O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.