1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.io.input;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21
22 /**
23 * A decorating input stream that counts the number of bytes that have passed
24 * through the stream so far.
25 * <p>
26 * A typical use case would be during debugging, to ensure that data is being
27 * read as expected.
28 *
29 * @author Marcelo Liberato
30 * @version $Id: CountingInputStream.java 471628 2006-11-06 04:06:45Z bayard $
31 */
32 public class CountingInputStream extends ProxyInputStream {
33
34 /** The count of bytes that have passed. */
35 private long count;
36
37 /**
38 * Constructs a new CountingInputStream.
39 *
40 * @param in the InputStream to delegate to
41 */
42 public CountingInputStream(InputStream in) {
43 super(in);
44 }
45
46 //-----------------------------------------------------------------------
47 /**
48 * Reads a number of bytes into the byte array, keeping count of the
49 * number read.
50 *
51 * @param b the buffer into which the data is read, not null
52 * @return the total number of bytes read into the buffer, -1 if end of stream
53 * @throws IOException if an I/O error occurs
54 * @see java.io.InputStream#read(byte[])
55 */
56 public int read(byte[] b) throws IOException {
57 int found = super.read(b);
58 this.count += (found >= 0) ? found : 0;
59 return found;
60 }
61
62 /**
63 * Reads a number of bytes into the byte array at a specific offset,
64 * keeping count of the number read.
65 *
66 * @param b the buffer into which the data is read, not null
67 * @param off the start offset in the buffer
68 * @param len the maximum number of bytes to read
69 * @return the total number of bytes read into the buffer, -1 if end of stream
70 * @throws IOException if an I/O error occurs
71 * @see java.io.InputStream#read(byte[], int, int)
72 */
73 public int read(byte[] b, int off, int len) throws IOException {
74 int found = super.read(b, off, len);
75 this.count += (found >= 0) ? found : 0;
76 return found;
77 }
78
79 /**
80 * Reads the next byte of data adding to the count of bytes received
81 * if a byte is successfully read.
82 *
83 * @return the byte read, -1 if end of stream
84 * @throws IOException if an I/O error occurs
85 * @see java.io.InputStream#read()
86 */
87 public int read() throws IOException {
88 int found = super.read();
89 this.count += (found >= 0) ? 1 : 0;
90 return found;
91 }
92
93 /**
94 * Skips the stream over the specified number of bytes, adding the skipped
95 * amount to the count.
96 *
97 * @param length the number of bytes to skip
98 * @return the actual number of bytes skipped
99 * @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 }