• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
TeeInputStream(InputStream input, OutputStream branch)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      */
TeeInputStream( InputStream input, OutputStream branch, boolean closeBranch)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      */
close()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      */
read()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      */
read(byte[] bts, int st, int end)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      */
read(byte[] bts)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