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
022 /**
023 * A decorating input stream that counts the number of bytes that have passed
024 * through the stream so far.
025 * <p>
026 * A typical use case would be during debugging, to ensure that data is being
027 * read as expected.
028 *
029 * @author Marcelo Liberato
030 * @version $Id: CountingInputStream.java 471628 2006-11-06 04:06:45Z bayard $
031 */
032 public class CountingInputStream extends ProxyInputStream {
033
034 /** The count of bytes that have passed. */
035 private long count;
036
037 /**
038 * Constructs a new CountingInputStream.
039 *
040 * @param in the InputStream to delegate to
041 */
042 public CountingInputStream(InputStream in) {
043 super(in);
044 }
045
046 //-----------------------------------------------------------------------
047 /**
048 * Reads a number of bytes into the byte array, keeping count of the
049 * number read.
050 *
051 * @param b the buffer into which the data is read, not null
052 * @return the total number of bytes read into the buffer, -1 if end of stream
053 * @throws IOException if an I/O error occurs
054 * @see java.io.InputStream#read(byte[])
055 */
056 public int read(byte[] b) throws IOException {
057 int found = super.read(b);
058 this.count += (found >= 0) ? found : 0;
059 return found;
060 }
061
062 /**
063 * Reads a number of bytes into the byte array at a specific offset,
064 * keeping count of the number read.
065 *
066 * @param b the buffer into which the data is read, not null
067 * @param off the start offset in the buffer
068 * @param len the maximum number of bytes to read
069 * @return the total number of bytes read into the buffer, -1 if end of stream
070 * @throws IOException if an I/O error occurs
071 * @see java.io.InputStream#read(byte[], int, int)
072 */
073 public int read(byte[] b, int off, int len) throws IOException {
074 int found = super.read(b, off, len);
075 this.count += (found >= 0) ? found : 0;
076 return found;
077 }
078
079 /**
080 * Reads the next byte of data adding to the count of bytes received
081 * if a byte is successfully read.
082 *
083 * @return the byte read, -1 if end of stream
084 * @throws IOException if an I/O error occurs
085 * @see java.io.InputStream#read()
086 */
087 public int read() throws IOException {
088 int found = super.read();
089 this.count += (found >= 0) ? 1 : 0;
090 return found;
091 }
092
093 /**
094 * Skips the stream over the specified number of bytes, adding the skipped
095 * amount to the count.
096 *
097 * @param length the number of bytes to skip
098 * @return the actual number of bytes skipped
099 * @throws IOException if an I/O error occurs
100 * @see java.io.InputStream#skip(long)
101 */
102 public long skip(final long length) throws IOException {
103 final long skip = super.skip(length);
104 this.count += skip;
105 return skip;
106 }
107
108 //-----------------------------------------------------------------------
109 /**
110 * The number of bytes that have passed through this stream.
111 * <p>
112 * NOTE: From v1.3 this method throws an ArithmeticException if the
113 * count is greater than can be expressed by an <code>int</code>.
114 * See {@link #getByteCount()} for a method using a <code>long</code>.
115 *
116 * @return the number of bytes accumulated
117 * @throws ArithmeticException if the byte count is too large
118 */
119 public synchronized int getCount() {
120 long result = getByteCount();
121 if (result > Integer.MAX_VALUE) {
122 throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
123 }
124 return (int) result;
125 }
126
127 /**
128 * Set the byte count back to 0.
129 * <p>
130 * NOTE: From v1.3 this method throws an ArithmeticException if the
131 * count is greater than can be expressed by an <code>int</code>.
132 * See {@link #resetByteCount()} for a method using a <code>long</code>.
133 *
134 * @return the count previous to resetting
135 * @throws ArithmeticException if the byte count is too large
136 */
137 public synchronized int resetCount() {
138 long result = resetByteCount();
139 if (result > Integer.MAX_VALUE) {
140 throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
141 }
142 return (int) result;
143 }
144
145 /**
146 * The number of bytes that have passed through this stream.
147 * <p>
148 * NOTE: This method is an alternative for <code>getCount()</code>
149 * and was added because that method returns an integer which will
150 * result in incorrect count for files over 2GB.
151 *
152 * @return the number of bytes accumulated
153 * @since Commons IO 1.3
154 */
155 public synchronized long getByteCount() {
156 return this.count;
157 }
158
159 /**
160 * Set the byte count back to 0.
161 * <p>
162 * NOTE: This method is an alternative for <code>resetCount()</code>
163 * and was added because that method returns an integer which will
164 * result in incorrect count for files over 2GB.
165 *
166 * @return the count previous to resetting
167 * @since Commons IO 1.3
168 */
169 public synchronized long resetByteCount() {
170 long tmp = this.count;
171 this.count = 0;
172 return tmp;
173 }
174
175 }