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 1307461 2012-03-30 15:12:29Z ggregory $ 035 * @since 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}. 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 }