Skip to content Skip to sidebar Skip to footer

Is There A Simple “tee” Filter For Java Input Streams?

For debugging purposes I would like to dump the content of an input stream into a file while it is processed. The stream is parsed by org.xml.sax.XMLReader which will consume the d

Solution 1:

Commons IO to the rescue! Check out TeeInputStream and TeeOutputStream.

Solution 2:

Not quite a ready rolled one, but this might be of interest. There is a TeeOutputStream implementation in the examples.

Solution 3:

Thanks for all the pointer. Here a copy of the class I created to solve my problem:

/**
 * <p>
 * Tee-Filters a Reader into an Writer.
 * </p>
 * 
 * @author "Martin Krischik" <martin.krischik@noser.com>
 * @version 1.0 $Revision: 1046 $
 * @since 1.0
 */publicclassTeeReaderextendsjava.io.Reader
{
   /**
    * <p>
    * Reader to read from
    * </p>
    */privatefinal java.io.Reader in;
   /**
    * <p>
    * Tee output to which read date is written before beeing passed on.
    * </p>
    */privatefinal java.io.Writer tee;

   /**
    * <p>
    * create new filter.
    * </p>
    * 
    * @param in
    *           Reader to read from
    * @param tee
    *           Tee output to which read date is written before beeing passed
    *           on.
    */publicTeeReader(final java.io.Reader in, final java.io.Writer tee)
   {
      this.in = in;
      this.tee = tee;
   } // TeeReader/**
    * <p>
    * Close the stream. Once a stream has been closed, further read(), ready(),
    * mark(), or reset() invocations will throw an IOException. Closing a
    * previously-closed stream, however, has no effect.
    * </p>
    * 
    * @throws java.io.IOException
    * @see java.io.Reader#close()
    */@Overridepublicvoidclose()throws java.io.IOException
   {
      this.in.close ();
   } // close/**
    * <p>
    * Reads characters into a portion of an array. This method will block until
    * some input is available, an I/O error occurs, or the end of the stream is
    * reached.
    * </p>
    * 
    * @param cbuf
    *           Destination buffer
    * @param off
    *           Offset at which to start storing characters
    * @param len
    *           Maximum number of characters to read
    * @return The number of characters read, or -1 if the end of the stream has
    *         been reached Throws:
    * @throws java.io.IOException
    * @see java.io.Reader#read(char[], int, int)
    */@Overridepublicintread(finalchar [] cbuf, finalint off, finalint len)throws java.io.IOException
   {
      finalintretval=this.in.read (cbuf, off, len);

      if (retval >= 0)
      {
         this.tee.write (cbuf, off, len);
      }
      else
      {
         this.tee.close ();
      } // ifreturn retval;
   } // read
} // TeeReader

Solution 4:

Here's a trivial output stream version (without exception handling):

publicclassTeeOutputStreamextendsOutputStream
   {
           private OutputStream[] streams;

           publicTeeOutputStream(final OutputStream ... streams)
           {
                   this.streams = streams;
           }

           @Overridepublicvoidclose()throws IOException
           {
                   for (OutputStream stream : streams)
                   {
                           stream.close();
                   }
           }

           @Overridepublicvoidflush()throws IOException
           {
                   for (OutputStream stream : streams)
                   {
                           stream.flush();
                   }

           }

           @Overridepublicvoidwrite(finalbyte[] buffer)throws IOException
           {
                   for (OutputStream stream : streams)
                   {
                           stream.write(buffer);
                   }

           }

           @Overridepublicvoidwrite(finalbyte[] buffer, finalint offset, finalint count)throws IOException
           {
                   for (OutputStream stream : streams)
                   {
                           stream.write(buffer, offset, count);
                   }

           }

           @Overridepublicvoidwrite(finalint i)throws IOException
           {
                   for (OutputStream stream : streams)
                   {
                           stream.write(i);
                   }
           }
   }

Solution 5:

I had the same problem. I wanted to be able to see what the Xml parser is getting so I could debug the server-side scripts. Ideally, you want to send the Xml to both the Xml parser and LogCat. You can use the enclosed clss InputStreamIntercept to do that. Just run the input stream through it:

final java.io.InputStreamcontent=newInputStreamIntercept(responseEntity.getContent());

Here is the class:

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import android.util.Log;

/**
 * This custom stream filter can intercept data being
 * sent to another stream and send it to LogCat. It is 
 * useful as a way to tell what is being sent to an
 * Xml parser.
 */publicclassInputStreamInterceptextendsFilterInputStream {

    /**
     * The string we build from data we input.
     */privateStringBuildersb=newStringBuilder();

    /**
     * Constructor.
     * @param in the stream we are intercepting
     */publicInputStreamIntercept(InputStream in) {
        super(in);
    }

    /**
     * Intercept read() and store the character for output
     * @returns -1 if nothing read or the character read
     */@Overridepublicintread()throws IOException {
        intret=super.read();
        if(ret >= 0) {
            newChar((byte)ret);
        }
        return ret;
    }

    /**
     * Intercept read and output the content to Log.i.
     */@Overridepublicintread(byte[] buffer, int offset, int count)throws IOException {
        intret=super.read(buffer, offset, count);
        for(int i=0;  i<ret;  i++) {
            newChar(buffer[i]);
        }
        return ret;
    }


    /**
     * Handle a new character. We output whenever we get a newline
     * @param ch
     */privatevoidnewChar(byte ch) {
        if(ch == 10) {
            Stringstr= sb.toString();
            if(str.equals("")) {
                Log.i("debug", "--blank line--");
            } else {
                Log.i("debug", str);
            }

            sb = newStringBuilder();
        } elseif(ch == 13) {
            // Skip this character
        } else {
            sb.append((char)ch);
        }
    }

    /**
     * Close the stream
     */@Overridepublicvoidclose()throws IOException {
        super.close();
        if(sb.length() > 0) {
            Log.i("debug", sb.toString());
        }
    }

}

Post a Comment for "Is There A Simple “tee” Filter For Java Input Streams?"