TeeReader.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.io.input;
- import static org.apache.commons.io.IOUtils.EOF;
- import java.io.IOException;
- import java.io.Reader;
- import java.io.Writer;
- import java.nio.CharBuffer;
- /**
- * Reader proxy that transparently writes a copy of all characters read from the proxied reader to a given Reader. Using
- * {@link #skip(long)} or {@link #mark(int)}/{@link #reset()} on the reader will result on some characters from the
- * reader being skipped or duplicated in the writer.
- * <p>
- * The proxied reader is closed when the {@link #close()} method is called on this proxy. You may configure whether the
- * reader closes the writer.
- * </p>
- *
- * @since 2.7
- */
- public class TeeReader extends ProxyReader {
- /**
- * The writer that will receive a copy of all characters read from the proxied reader.
- */
- private final Writer branch;
- /**
- * Flag for closing the associated writer when this reader is closed.
- */
- private final boolean closeBranch;
- /**
- * Constructs a TeeReader that proxies the given {@link Reader} and copies all read characters to the given
- * {@link Writer}. The given writer will not be closed when this reader gets closed.
- *
- * @param input reader to be proxied
- * @param branch writer that will receive a copy of all characters read
- */
- public TeeReader(final Reader input, final Writer branch) {
- this(input, branch, false);
- }
- /**
- * Constructs a TeeReader that proxies the given {@link Reader} and copies all read characters to the given
- * {@link Writer}. The given writer will be closed when this reader gets closed if the closeBranch parameter is
- * {@code true}.
- *
- * @param input reader to be proxied
- * @param branch writer that will receive a copy of all characters read
- * @param closeBranch flag for closing also the writer when this reader is closed
- */
- public TeeReader(final Reader input, final Writer branch, final boolean closeBranch) {
- super(input);
- this.branch = branch;
- this.closeBranch = closeBranch;
- }
- /**
- * Closes the proxied reader and, if so configured, the associated writer. An exception thrown from the reader will
- * not prevent closing of the writer.
- *
- * @throws IOException if either the reader or writer could not be closed
- */
- @Override
- public void close() throws IOException {
- try {
- super.close();
- } finally {
- if (closeBranch) {
- branch.close();
- }
- }
- }
- /**
- * Reads a single character from the proxied reader and writes it to the associated writer.
- *
- * @return next character from the reader, or -1 if the reader has ended
- * @throws IOException if the reader could not be read (or written)
- */
- @Override
- public int read() throws IOException {
- final int ch = super.read();
- if (ch != EOF) {
- branch.write(ch);
- }
- return ch;
- }
- /**
- * Reads characters from the proxied reader and writes the read characters to the associated writer.
- *
- * @param chr character buffer
- * @return number of characters read, or -1 if the reader has ended
- * @throws IOException if the reader could not be read (or written)
- */
- @Override
- public int read(final char[] chr) throws IOException {
- final int n = super.read(chr);
- if (n != EOF) {
- branch.write(chr, 0, n);
- }
- return n;
- }
- /**
- * Reads characters from the proxied reader and writes the read characters to the associated writer.
- *
- * @param chr character buffer
- * @param st start offset within the buffer
- * @param end maximum number of characters to read
- * @return number of characters read, or -1 if the reader has ended
- * @throws IOException if the reader could not be read (or written)
- */
- @Override
- public int read(final char[] chr, final int st, final int end) throws IOException {
- final int n = super.read(chr, st, end);
- if (n != EOF) {
- branch.write(chr, st, n);
- }
- return n;
- }
- /**
- * Reads characters from the proxied reader and writes the read characters to the associated writer.
- *
- * @param target character buffer
- * @return number of characters read, or -1 if the reader has ended
- * @throws IOException if the reader could not be read (or written)
- */
- @Override
- public int read(final CharBuffer target) throws IOException {
- final int originalPosition = target.position();
- final int n = super.read(target);
- if (n != EOF) {
- // Appending can only be done after resetting the CharBuffer to the
- // right position and limit.
- final int newPosition = target.position();
- final int newLimit = target.limit();
- try {
- target.position(originalPosition).limit(newPosition);
- branch.append(target);
- } finally {
- // Reset the CharBuffer as if the appending never happened.
- target.position(newPosition).limit(newLimit);
- }
- }
- return n;
- }
- }