ReaderPump.java

/***************************************************************************
   Copyright 2008 Emily Estes

   Licensed 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 net.metanotion.io;


import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

import net.metanotion.util.Pump;

/** Create a "pump" that will transfer characters from an input {@link java.io.Reader}
to an output {@link java.io.Writer}. The methods of this object will copy until various
"blocking" or end of stream behaviors occur. Note: at present this class does not
make use of any of the NIO classes. That is an obvious improvement to make, but it
has not been a huge priority at the moment. */
public final class ReaderPump implements Pump<IOException> {
	/** The default size of the buffer to read into before writing. */
	private static final int defaultBlockSize = 2048;

	/** The input Reader to transfer characters from. */
	private final Reader in;
	/** The output Writer to transfer characters to. */
	private final Writer out;
	/** The maximum block size to use when transfering characters. */
	private final int blockSize;

	/** Create a reader pump with the default block size.
		@param in The reader to transfer characters from.
		@param out The writer to transfer characters to.
	*/
	public ReaderPump(final Reader in, final Writer out) { this(in, out, defaultBlockSize); }

	/** Create a reader pump with a custom block size.
		@param in The reader to transfer characters from.
		@param out The writer to transfer characters to.
		@param blockSize The size of the transfer buffer.
	*/
	public ReaderPump(final Reader in, final Writer out, final int blockSize) {
		this.in = in;
		this.out = out;
		this.blockSize = blockSize;
	}

	/** Attempt to transfer every character from the reader to the writer.
		This method blocks until either {@link java.io.Reader#read(char[])} returns 0 characters read
		or an {@link java.io.EOFException} occurs. If either stream throws an {@link java.io.IOException}
		the transfer is interrupted and the exeption is propagated to the caller.
		@throws java.io.IOException if either in or out throws one.
	*/
	@Override public void pumpAll() throws IOException {
		final char[] buffer = new char[blockSize];
		try {
			while(true) {
				final int len = in.read(buffer);
				if(len < 0) { break; }
				out.write(buffer, 0, len);
			}
		} catch(EOFException eof) { }
	}

	/** Transfer characters from in to out as long as {@link java.io.Reader#ready} returns true.
		or an {@link java.io.EOFException} occurs. If either stream throws an {@link java.io.IOException}
		the transfer is interrupted and the exeption is propagated to the caller.
		@throws java.io.IOException if either in or out throws one.
	*/
	@Override public void pumpUntilBlocked() throws IOException {
		final char[] buffer = new char[blockSize];
		try {
			while(in.ready()) {
				final int len = in.read(buffer);
				if(len < 0) { break; }
				out.write(buffer, 0, len);
			}
		} catch(EOFException eof) { }
	}

	/** Transfer n characters from in to out as long unless an {@link java.io.EOFException} occurs or
		{@link java.io.Reader#read(char[])} returns 0 characters read. If either stream throws an
		{@link java.io.IOException} the transfer is interrupted and the exeption is propagated to the caller.
		@param n The number of characters to transfer.
		@return The actual number of characters transferred. Will be less than n if
			{@link java.io.Reader#read(char[])} returns 0 before n characters are read.
		@throws java.io.IOException if either in or out throws one.
	*/
	@Override public int pumpCount(final int n) throws IOException {
		final char[] buffer = new char[blockSize];
		int read = 0;
		try {
			while(read < n) {
				int len;
				if((n - read) < blockSize) {
					len = in.read(buffer, 0, n - read);
				} else {
					len = in.read(buffer);
				}
				if(len < 0) { break; }
				out.write(buffer, 0, len);
				read += len;
			}
		} catch(EOFException eof) { }
		return read;
	}

	/** Transfer n characters from in to out as long unless an {@link java.io.EOFException} occurs or
		{@link java.io.Reader#read(char[])} returns 0 characters read OR {@link java.io.Reader#ready} returns
		false. If either stream throws an {@link java.io.IOException} the transfer is interrupted and the
		exeption is propagated to the caller.
		@param n The number of characters to transfer.
		@return The actual number of characters transferred. Will be less than n if
			{@link java.io.Reader#read(char[])} returns 0 before n characters are read or {@link java.io.Reader#ready}
			returns false before n characters are read, or an {@link java.io.EOFException} occurs..
		@throws java.io.IOException if either in or out throws one.
	*/
	@Override public int pumpCountUntilBlocked(final int n) throws IOException {
		final char[] buffer = new char[blockSize];
		int read = 0;
		try {
			while((read < n) && (in.ready())) {
				int len;
				if((n - read) < blockSize) {
					len = in.read(buffer, 0, n - read);
				} else {
					len = in.read(buffer);
				}
				if(len < 0) { break; }
				out.write(buffer, 0, len);
				read += len;
			}
		} catch(EOFException eof) { }
		return read;
	}
}