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 1004079 2010-10-04 01:11:27Z niallp $
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        /**
049         * Skips the stream over the specified number of bytes, adding the skipped
050         * amount to the count.
051         *
052         * @param length  the number of bytes to skip
053         * @return the actual number of bytes skipped
054         * @throws IOException if an I/O error occurs
055         * @see java.io.InputStream#skip(long)
056         */
057        @Override
058        public synchronized long skip(final long length) throws IOException {
059            final long skip = super.skip(length);
060            this.count += skip;
061            return skip;
062        }
063    
064        /**
065         * Adds the number of read bytes to the count.
066         *
067         * @param n number of bytes read, or -1 if no more bytes are available
068         * @since Commons IO 2.0
069         */
070        @Override
071        protected synchronized void afterRead(int n) {
072            if (n != -1) {
073                this.count += n;
074            }
075        }
076    
077        //-----------------------------------------------------------------------
078        /**
079         * The number of bytes that have passed through this stream.
080         * <p>
081         * NOTE: From v1.3 this method throws an ArithmeticException if the
082         * count is greater than can be expressed by an <code>int</code>.
083         * See {@link #getByteCount()} for a method using a <code>long</code>.
084         *
085         * @return the number of bytes accumulated
086         * @throws ArithmeticException if the byte count is too large
087         */
088        public int getCount() {
089            long result = getByteCount();
090            if (result > Integer.MAX_VALUE) {
091                throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
092            }
093            return (int) result;
094        }
095    
096        /** 
097         * Set the byte count back to 0. 
098         * <p>
099         * NOTE: From v1.3 this method throws an ArithmeticException if the
100         * count is greater than can be expressed by an <code>int</code>.
101         * See {@link #resetByteCount()} for a method using a <code>long</code>.
102         *
103         * @return the count previous to resetting
104         * @throws ArithmeticException if the byte count is too large
105         */
106        public int resetCount() {
107            long result = resetByteCount();
108            if (result > Integer.MAX_VALUE) {
109                throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
110            }
111            return (int) result;
112        }
113    
114        /**
115         * The number of bytes that have passed through this stream.
116         * <p>
117         * NOTE: This method is an alternative for <code>getCount()</code>
118         * and was added because that method returns an integer which will
119         * result in incorrect count for files over 2GB.
120         *
121         * @return the number of bytes accumulated
122         * @since Commons IO 1.3
123         */
124        public synchronized long getByteCount() {
125            return this.count;
126        }
127    
128        /** 
129         * Set the byte count back to 0. 
130         * <p>
131         * NOTE: This method is an alternative for <code>resetCount()</code>
132         * and was added because that method returns an integer which will
133         * result in incorrect count for files over 2GB.
134         *
135         * @return the count previous to resetting
136         * @since Commons IO 1.3
137         */
138        public synchronized long resetByteCount() {
139            long tmp = this.count;
140            this.count = 0;
141            return tmp;
142        }
143    
144    }