1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io.output; 18 19 import java.io.IOException; 20 import java.io.OutputStream; 21 22 /** 23 * Classic splitter of {@link OutputStream}. Named after the UNIX 'tee' command. It allows a stream to be branched off 24 * so there are now two streams. 25 */ 26 public class TeeOutputStream extends ProxyOutputStream { 27 28 /** 29 * The second OutputStream to write to. 30 * 31 * TODO Make private and final in 3.0. 32 */ 33 protected OutputStream branch; 34 35 /** 36 * Constructs a TeeOutputStream. 37 * 38 * @param out the main OutputStream 39 * @param branch the second OutputStream 40 */ 41 public TeeOutputStream(final OutputStream out, final OutputStream branch) { 42 super(out); 43 this.branch = branch; 44 } 45 46 /** 47 * Closes both output streams. 48 * <p> 49 * If closing the main output stream throws an exception, attempt to close the branch output stream. 50 * </p> 51 * 52 * <p> 53 * If closing the main and branch output streams both throw exceptions, which exceptions is thrown by this method is 54 * currently unspecified and subject to change. 55 * </p> 56 * 57 * @throws IOException if an I/O error occurs. 58 */ 59 @Override 60 public void close() throws IOException { 61 try { 62 super.close(); 63 } finally { 64 this.branch.close(); 65 } 66 } 67 68 /** 69 * Flushes both streams. 70 * 71 * @throws IOException if an I/O error occurs. 72 */ 73 @Override 74 public void flush() throws IOException { 75 super.flush(); 76 this.branch.flush(); 77 } 78 79 /** 80 * Writes the bytes to both streams. 81 * 82 * @param b the bytes to write 83 * @throws IOException if an I/O error occurs. 84 */ 85 @Override 86 public synchronized void write(final byte[] b) throws IOException { 87 super.write(b); 88 this.branch.write(b); 89 } 90 91 /** 92 * Writes the specified bytes to both streams. 93 * 94 * @param b the bytes to write 95 * @param off The start offset 96 * @param len The number of bytes to write 97 * @throws IOException if an I/O error occurs. 98 */ 99 @Override 100 public synchronized void write(final byte[] b, final int off, final int len) throws IOException { 101 super.write(b, off, len); 102 this.branch.write(b, off, len); 103 } 104 105 /** 106 * Writes a byte to both streams. 107 * 108 * @param b the byte to write 109 * @throws IOException if an I/O error occurs. 110 */ 111 @Override 112 public synchronized void write(final int b) throws IOException { 113 super.write(b); 114 this.branch.write(b); 115 } 116 117 }