Home | History | Annotate | Download | only in input
      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.input;
     18 
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.io.OutputStream;
     22 
     23 /**
     24  * InputStream proxy that transparently writes a copy of all bytes read
     25  * from the proxied stream to a given OutputStream. Using {@link #skip(long)}
     26  * or {@link #mark(int)}/{@link #reset()} on the stream will result on some
     27  * bytes from the input stream being skipped or duplicated in the output
     28  * stream.
     29  * <p>
     30  * The proxied input stream is closed when the {@link #close()} method is
     31  * called on this proxy. It is configurable whether the associated output
     32  * stream will also closed.
     33  *
     34  * @version $Id: TeeInputStream.java 587913 2007-10-24 15:47:30Z niallp $
     35  * @since Commons IO 1.4
     36  */
     37 public class TeeInputStream extends ProxyInputStream {
     38 
     39     /**
     40      * The output stream that will receive a copy of all bytes read from the
     41      * proxied input stream.
     42      */
     43     private final OutputStream branch;
     44 
     45     /**
     46      * Flag for closing also the associated output stream when this
     47      * stream is closed.
     48      */
     49     private final boolean closeBranch;
     50 
     51     /**
     52      * Creates a TeeInputStream that proxies the given {@link InputStream}
     53      * and copies all read bytes to the given {@link OutputStream}. The given
     54      * output stream will not be closed when this stream gets closed.
     55      *
     56      * @param input input stream to be proxied
     57      * @param branch output stream that will receive a copy of all bytes read
     58      */
     59     public TeeInputStream(InputStream input, OutputStream branch) {
     60         this(input, branch, false);
     61     }
     62 
     63     /**
     64      * Creates a TeeInputStream that proxies the given {@link InputStream}
     65      * and copies all read bytes to the given {@link OutputStream}. The given
     66      * output stream will be closed when this stream gets closed if the
     67      * closeBranch parameter is <code>true</code>.
     68      *
     69      * @param input input stream to be proxied
     70      * @param branch output stream that will receive a copy of all bytes read
     71      * @param closeBranch flag for closing also the output stream when this
     72      *                    stream is closed
     73      */
     74     public TeeInputStream(
     75             InputStream input, OutputStream branch, boolean closeBranch) {
     76         super(input);
     77         this.branch = branch;
     78         this.closeBranch = closeBranch;
     79     }
     80 
     81     /**
     82      * Closes the proxied input stream and, if so configured, the associated
     83      * output stream. An exception thrown from one stream will not prevent
     84      * closing of the other stream.
     85      *
     86      * @throws IOException if either of the streams could not be closed
     87      */
     88     public void close() throws IOException {
     89         try {
     90             super.close();
     91         } finally {
     92             if (closeBranch) {
     93                 branch.close();
     94             }
     95         }
     96     }
     97 
     98     /**
     99      * Reads a single byte from the proxied input stream and writes it to
    100      * the associated output stream.
    101      *
    102      * @return next byte from the stream, or -1 if the stream has ended
    103      * @throws IOException if the stream could not be read (or written)
    104      */
    105     public int read() throws IOException {
    106         int ch = super.read();
    107         if (ch != -1) {
    108             branch.write(ch);
    109         }
    110         return ch;
    111     }
    112 
    113     /**
    114      * Reads bytes from the proxied input stream and writes the read bytes
    115      * to the associated output stream.
    116      *
    117      * @param bts byte buffer
    118      * @param st start offset within the buffer
    119      * @param end maximum number of bytes to read
    120      * @return number of bytes read, or -1 if the stream has ended
    121      * @throws IOException if the stream could not be read (or written)
    122      */
    123     public int read(byte[] bts, int st, int end) throws IOException {
    124         int n = super.read(bts, st, end);
    125         if (n != -1) {
    126             branch.write(bts, st, n);
    127         }
    128         return n;
    129     }
    130 
    131     /**
    132      * Reads bytes from the proxied input stream and writes the read bytes
    133      * to the associated output stream.
    134      *
    135      * @param bts byte buffer
    136      * @return number of bytes read, or -1 if the stream has ended
    137      * @throws IOException if the stream could not be read (or written)
    138      */
    139     public int read(byte[] bts) throws IOException {
    140         int n = super.read(bts);
    141         if (n != -1) {
    142             branch.write(bts, 0, n);
    143         }
    144         return n;
    145     }
    146 
    147 }
    148