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.output;
018    
019    import java.io.IOException;
020    import java.io.OutputStream;
021    
022    /**
023     * A decorating output 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     * written as expected.
028     *
029     * @version $Id: CountingOutputStream.java 471628 2006-11-06 04:06:45Z bayard $
030     */
031    public class CountingOutputStream extends ProxyOutputStream {
032    
033        /** The count of bytes that have passed. */
034        private long count;
035    
036        /**
037         * Constructs a new CountingOutputStream.
038         * 
039         * @param out  the OutputStream to write to
040         */
041        public CountingOutputStream( OutputStream out ) {
042            super(out);
043        }
044    
045        //-----------------------------------------------------------------------
046        /**
047         * Writes the contents of the specified byte array to this output stream
048         * keeping count of the number of bytes written.
049         *
050         * @param b  the bytes to write, not null
051         * @throws IOException if an I/O error occurs
052         * @see java.io.OutputStream#write(byte[])
053         */
054        public void write(byte[] b) throws IOException {
055            count += b.length;
056            super.write(b);
057        }
058    
059        /**
060         * Writes a portion of the specified byte array to this output stream
061         * keeping count of the number of bytes written.
062         *
063         * @param b  the bytes to write, not null
064         * @param off  the start offset in the buffer
065         * @param len  the maximum number of bytes to write
066         * @throws IOException if an I/O error occurs
067         * @see java.io.OutputStream#write(byte[], int, int)
068         */
069        public void write(byte[] b, int off, int len) throws IOException {
070            count += len;
071            super.write(b, off, len);
072        }
073    
074        /**
075         * Writes a single byte to the output stream adding to the count of the
076         * number of bytes written.
077         *
078         * @param b  the byte to write
079         * @throws IOException if an I/O error occurs
080         * @see java.io.OutputStream#write(int)
081         */
082        public void write(int b) throws IOException {
083            count++;
084            super.write(b);
085        }
086    
087        //-----------------------------------------------------------------------
088        /**
089         * The number of bytes that have passed through this stream.
090         * <p>
091         * NOTE: From v1.3 this method throws an ArithmeticException if the
092         * count is greater than can be expressed by an <code>int</code>.
093         * See {@link #getByteCount()} for a method using a <code>long</code>.
094         *
095         * @return the number of bytes accumulated
096         * @throws ArithmeticException if the byte count is too large
097         */
098        public synchronized int getCount() {
099            long result = getByteCount();
100            if (result > Integer.MAX_VALUE) {
101                throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
102            }
103            return (int) result;
104        }
105    
106        /** 
107         * Set the byte count back to 0. 
108         * <p>
109         * NOTE: From v1.3 this method throws an ArithmeticException if the
110         * count is greater than can be expressed by an <code>int</code>.
111         * See {@link #resetByteCount()} for a method using a <code>long</code>.
112         *
113         * @return the count previous to resetting
114         * @throws ArithmeticException if the byte count is too large
115         */
116        public synchronized int resetCount() {
117            long result = resetByteCount();
118            if (result > Integer.MAX_VALUE) {
119                throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int");
120            }
121            return (int) result;
122        }
123    
124        /**
125         * The number of bytes that have passed through this stream.
126         * <p>
127         * NOTE: This method is an alternative for <code>getCount()</code>.
128         * It was added because that method returns an integer which will
129         * result in incorrect count for files over 2GB.
130         *
131         * @return the number of bytes accumulated
132         * @since Commons IO 1.3
133         */
134        public synchronized long getByteCount() {
135            return this.count;
136        }
137    
138        /** 
139         * Set the byte count back to 0. 
140         * <p>
141         * NOTE: This method is an alternative for <code>resetCount()</code>.
142         * It was added because that method returns an integer which will
143         * result in incorrect count for files over 2GB.
144         *
145         * @return the count previous to resetting
146         * @since Commons IO 1.3
147         */
148        public synchronized long resetByteCount() {
149            long tmp = this.count;
150            this.count = 0;
151            return tmp;
152        }
153    
154    }