TeeInputStream.java

  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. import static org.apache.commons.io.IOUtils.EOF;

  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;

  22. /**
  23.  * InputStream proxy that transparently writes a copy of all bytes read
  24.  * from the proxied stream to a given OutputStream. Using {@link #skip(long)}
  25.  * or {@link #mark(int)}/{@link #reset()} on the stream will result on some
  26.  * bytes from the input stream being skipped or duplicated in the output
  27.  * stream.
  28.  * <p>
  29.  * The proxied input stream is closed when the {@link #close()} method is
  30.  * called on this proxy. You may configure whether the input stream closes the
  31.  * output stream.
  32.  * </p>
  33.  *
  34.  * @since 1.4
  35.  * @see ObservableInputStream
  36.  */
  37. public class TeeInputStream extends ProxyInputStream {

  38.     /**
  39.      * The output stream that will receive a copy of all bytes read from the
  40.      * proxied input stream.
  41.      */
  42.     private final OutputStream branch;

  43.     /**
  44.      * Flag for closing the associated output stream when this stream is closed.
  45.      */
  46.     private final boolean closeBranch;

  47.     /**
  48.      * Constructs a TeeInputStream that proxies the given {@link InputStream}
  49.      * and copies all read bytes to the given {@link OutputStream}. The given
  50.      * output stream will not be closed when this stream gets closed.
  51.      *
  52.      * @param input input stream to be proxied
  53.      * @param branch output stream that will receive a copy of all bytes read
  54.      */
  55.     public TeeInputStream(final InputStream input, final OutputStream branch) {
  56.         this(input, branch, false);
  57.     }

  58.     /**
  59.      * Constructs a TeeInputStream that proxies the given {@link InputStream}
  60.      * and copies all read bytes to the given {@link OutputStream}. The given
  61.      * output stream will be closed when this stream gets closed if the
  62.      * closeBranch parameter is {@code true}.
  63.      *
  64.      * @param input input stream to be proxied
  65.      * @param branch output stream that will receive a copy of all bytes read
  66.      * @param closeBranch flag for closing also the output stream when this
  67.      *                    stream is closed
  68.      */
  69.     public TeeInputStream(
  70.             final InputStream input, final OutputStream branch, final boolean closeBranch) {
  71.         super(input);
  72.         this.branch = branch;
  73.         this.closeBranch = closeBranch;
  74.     }

  75.     /**
  76.      * Closes the proxied input stream and, if so configured, the associated
  77.      * output stream. An exception thrown from one stream will not prevent
  78.      * closing of the other stream.
  79.      *
  80.      * @throws IOException if either of the streams could not be closed
  81.      */
  82.     @Override
  83.     public void close() throws IOException {
  84.         try {
  85.             super.close();
  86.         } finally {
  87.             if (closeBranch) {
  88.                 branch.close();
  89.             }
  90.         }
  91.     }

  92.     /**
  93.      * Reads a single byte from the proxied input stream and writes it to
  94.      * the associated output stream.
  95.      *
  96.      * @return next byte from the stream, or -1 if the stream has ended
  97.      * @throws IOException if the stream could not be read (or written)
  98.      */
  99.     @Override
  100.     public int read() throws IOException {
  101.         final int ch = super.read();
  102.         if (ch != EOF) {
  103.             branch.write(ch);
  104.         }
  105.         return ch;
  106.     }

  107.     /**
  108.      * Reads bytes from the proxied input stream and writes the read bytes
  109.      * to the associated output stream.
  110.      *
  111.      * @param bts byte buffer
  112.      * @return number of bytes read, or -1 if the stream has ended
  113.      * @throws IOException if the stream could not be read (or written)
  114.      */
  115.     @Override
  116.     public int read(final byte[] bts) throws IOException {
  117.         final int n = super.read(bts);
  118.         if (n != EOF) {
  119.             branch.write(bts, 0, n);
  120.         }
  121.         return n;
  122.     }

  123.     /**
  124.      * Reads bytes from the proxied input stream and writes the read bytes
  125.      * to the associated output stream.
  126.      *
  127.      * @param bts byte buffer
  128.      * @param st start offset within the buffer
  129.      * @param end maximum number of bytes to read
  130.      * @return number of bytes read, or -1 if the stream has ended
  131.      * @throws IOException if the stream could not be read (or written)
  132.      */
  133.     @Override
  134.     public int read(final byte[] bts, final int st, final int end) throws IOException {
  135.         final int n = super.read(bts, st, end);
  136.         if (n != EOF) {
  137.             branch.write(bts, st, n);
  138.         }
  139.         return n;
  140.     }

  141. }