001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io.input;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.OutputStream;
022
023 /**
024 * InputStream proxy that transparently writes a copy of all bytes read
025 * from the proxied stream to a given OutputStream. Using {@link #skip(long)}
026 * or {@link #mark(int)}/{@link #reset()} on the stream will result on some
027 * bytes from the input stream being skipped or duplicated in the output
028 * stream.
029 * <p>
030 * The proxied input stream is closed when the {@link #close()} method is
031 * called on this proxy. It is configurable whether the associated output
032 * stream will also closed.
033 *
034 * @version $Id: TeeInputStream.java 659817 2008-05-24 13:23:10Z niallp $
035 * @since Commons IO 1.4
036 */
037 public class TeeInputStream extends ProxyInputStream {
038
039 /**
040 * The output stream that will receive a copy of all bytes read from the
041 * proxied input stream.
042 */
043 private final OutputStream branch;
044
045 /**
046 * Flag for closing also the associated output stream when this
047 * stream is closed.
048 */
049 private final boolean closeBranch;
050
051 /**
052 * Creates a TeeInputStream that proxies the given {@link InputStream}
053 * and copies all read bytes to the given {@link OutputStream}. The given
054 * output stream will not be closed when this stream gets closed.
055 *
056 * @param input input stream to be proxied
057 * @param branch output stream that will receive a copy of all bytes read
058 */
059 public TeeInputStream(InputStream input, OutputStream branch) {
060 this(input, branch, false);
061 }
062
063 /**
064 * Creates a TeeInputStream that proxies the given {@link InputStream}
065 * and copies all read bytes to the given {@link OutputStream}. The given
066 * output stream will be closed when this stream gets closed if the
067 * closeBranch parameter is <code>true</code>.
068 *
069 * @param input input stream to be proxied
070 * @param branch output stream that will receive a copy of all bytes read
071 * @param closeBranch flag for closing also the output stream when this
072 * stream is closed
073 */
074 public TeeInputStream(
075 InputStream input, OutputStream branch, boolean closeBranch) {
076 super(input);
077 this.branch = branch;
078 this.closeBranch = closeBranch;
079 }
080
081 /**
082 * Closes the proxied input stream and, if so configured, the associated
083 * output stream. An exception thrown from one stream will not prevent
084 * closing of the other stream.
085 *
086 * @throws IOException if either of the streams could not be closed
087 */
088 @Override
089 public void close() throws IOException {
090 try {
091 super.close();
092 } finally {
093 if (closeBranch) {
094 branch.close();
095 }
096 }
097 }
098
099 /**
100 * Reads a single byte from the proxied input stream and writes it to
101 * the associated output stream.
102 *
103 * @return next byte from the stream, or -1 if the stream has ended
104 * @throws IOException if the stream could not be read (or written)
105 */
106 @Override
107 public int read() throws IOException {
108 int ch = super.read();
109 if (ch != -1) {
110 branch.write(ch);
111 }
112 return ch;
113 }
114
115 /**
116 * Reads bytes from the proxied input stream and writes the read bytes
117 * to the associated output stream.
118 *
119 * @param bts byte buffer
120 * @param st start offset within the buffer
121 * @param end maximum number of bytes to read
122 * @return number of bytes read, or -1 if the stream has ended
123 * @throws IOException if the stream could not be read (or written)
124 */
125 @Override
126 public int read(byte[] bts, int st, int end) throws IOException {
127 int n = super.read(bts, st, end);
128 if (n != -1) {
129 branch.write(bts, st, n);
130 }
131 return n;
132 }
133
134 /**
135 * Reads bytes from the proxied input stream and writes the read bytes
136 * to the associated output stream.
137 *
138 * @param bts byte buffer
139 * @return number of bytes read, or -1 if the stream has ended
140 * @throws IOException if the stream could not be read (or written)
141 */
142 @Override
143 public int read(byte[] bts) throws IOException {
144 int n = super.read(bts);
145 if (n != -1) {
146 branch.write(bts, 0, n);
147 }
148 return n;
149 }
150
151 }