Multitarget Output Streams

As a final example, I present two slightly unusual filter output streams that direct their data to multiple underlying streams. The TeeOutputStream class, given in Example 6.5, has not one but two underlying streams. The TeeOutputStream does not modify the data that’s written in any way; it merely writes it on both of its underlying streams.

Example 6-5. The TeeOutputStream Class



public class TeeOutputStream extends FilterOutputStream {

  OutputStream out1;
  OutputStream out2;

  public TeeOutputStream(OutputStream stream1, OutputStream stream2) {
    out1 = stream1;
    out2 = stream2;

  public synchronized void write(int b) throws IOException {

  public synchronized void write(byte[] data, int offset, int length) 
   throws IOException {
    out1.write(data, offset, length);
    out2.write(data, offset, length);

  public void flush() throws IOException {
  public void close() throws IOException {

It would be possible to store one of the output streams in FilterOutputStream’s protected out field and the other in a field in this class. However, it’s simpler and cleaner to maintain the parallelism between the two streams by storing them both in the TeeOutputStream class.

I’ve synchronized the write() methods to make sure that two different threads don’t try to write to the same TeeOutputStream at the same time. Depending on unpredictable ...

Get Java I/O now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.