Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write data to two java.io.OutputStream objects at once?

I'm looking for magical Java class that will allow me to do something like this:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));

MultiOutputStream outStream = new MultiOutputStream(byteStream, fileStream);

outStream.write("Hello world".getBytes());

Basically, I want tee for OutputStreams in Java. Any ideas?

Thanks!

like image 251
daveslab Avatar asked Nov 02 '11 21:11

daveslab


3 Answers

Try the Apache Commons TeeOutputStream.

like image 76
Dave Newton Avatar answered Oct 11 '22 15:10

Dave Newton


Just roll your own. There isn't any magic at all. Using Apache's TeeOutputStream you would basically use the code below. Of course using the Apache Commons I/O library you can leverage other classes, but sometimes it is nice to actually write something for yourself. :)

public final class TeeOutputStream extends OutputStream {

  private final OutputStream out;
  private final OutputStream tee;

  public TeeOutputStream(OutputStream out, OutputStream tee) {
    if (out == null)
      throw new NullPointerException();
    else if (tee == null)
      throw new NullPointerException();

    this.out = out;
    this.tee = tee;
  }

  @Override
  public void write(int b) throws IOException {
    out.write(b);
    tee.write(b);
  }

  @Override
  public void write(byte[] b) throws IOException {
    out.write(b);
    tee.write(b);
  }

  @Override
  public void write(byte[] b, int off, int len) throws IOException {
    out.write(b, off, len);
    tee.write(b, off, len);
  }

  @Override
  public void flush() throws IOException {
    out.flush();
    tee.flush();
  }

  @Override
  public void close() throws IOException {
    try {
      out.close();
    } finally {
      tee.close();
    }
  }
}

Testing with the above class with the following

public static void main(String[] args) throws IOException {
  TeeOutputStream out = new TeeOutputStream(System.out, System.out);
  out.write("Hello world!".getBytes());
  out.flush();
  out.close();
}

would print Hello World!Hello World!.

(Note: the overridden close() could use some care tho' :)

like image 26
Kohányi Róbert Avatar answered Oct 11 '22 16:10

Kohányi Róbert


Just found this thread beacause I had to face the same problem. If someone wants to see my solution (java7 code):

package Core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class MultiOutputStream extends OutputStream {

private List<OutputStream> out;

public MultiOutputStream(List<OutputStream> outStreams) {

    this.out = new LinkedList<OutputStream>();

    for (Iterator<OutputStream> i = outStreams.iterator(); i.hasNext();) {
        OutputStream outputStream = (OutputStream) i.next();

        if(outputStream == null){
            throw new NullPointerException();
        }
        this.out.add(outputStream);
    }
}

@Override
public void write(int arg0) throws IOException {

    for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
        OutputStream var = (OutputStream) i.next();

        var.write(arg0);
    }
}

@Override
public void write(byte[] b) throws IOException{

    for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
        OutputStream var = (OutputStream) i.next();

        var.write(b);
    }
}

@Override
public void write(byte[] b, int off, int len) throws IOException{

    for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
        OutputStream var = (OutputStream) i.next();

        var.write(b, off, len);
    }
}

@Override
public void close() throws IOException{

    for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
        OutputStream var = (OutputStream) i.next();

        var.close();
    }
}

@Override
public void flush() throws IOException{

    for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
        OutputStream var = (OutputStream) i.next();

        var.flush();
    }
}

}

Works fine so far, just tested some basic operation, e.g. setting up a MultiOutputStream from the System.out Stream and 2 PrintStreams each writing into a seperate log. I used

System.setOut(multiOutputStream);

to write to my terminal screen and two logs which worked without any problems.

like image 4
Lejon Doering Avatar answered Oct 11 '22 16:10

Lejon Doering