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