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.tika.io; 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 * @since Apache Tika 0.4, copied from Commons IO 1.4 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 @Override 57 public int read(byte[] b) throws IOException { 58 int found = super.read(b); 59 this.count += (found >= 0) ? found : 0; 60 return found; 61 } 62 63 /** 64 * Reads a number of bytes into the byte array at a specific offset, 65 * keeping count of the number read. 66 * 67 * @param b the buffer into which the data is read, not null 68 * @param off the start offset in the buffer 69 * @param len the maximum number of bytes to read 70 * @return the total number of bytes read into the buffer, -1 if end of stream 71 * @throws IOException if an I/O error occurs 72 * @see java.io.InputStream#read(byte[], int, int) 73 */ 74 @Override 75 public int read(byte[] b, int off, int len) throws IOException { 76 int found = super.read(b, off, len); 77 this.count += (found >= 0) ? found : 0; 78 return found; 79 } 80 81 /** 82 * Reads the next byte of data adding to the count of bytes received 83 * if a byte is successfully read. 84 * 85 * @return the byte read, -1 if end of stream 86 * @throws IOException if an I/O error occurs 87 * @see java.io.InputStream#read() 88 */ 89 @Override 90 public int read() throws IOException { 91 int found = super.read(); 92 this.count += (found >= 0) ? 1 : 0; 93 return found; 94 } 95 96 /** 97 * Skips the stream over the specified number of bytes, adding the skipped 98 * amount to the count. 99 * 100 * @param length the number of bytes to skip 101 * @return the actual number of bytes skipped 102 * @throws IOException if an I/O error occurs 103 * @see java.io.InputStream#skip(long) 104 */ 105 @Override 106 public long skip(final long length) throws IOException { 107 final long skip = super.skip(length); 108 this.count += skip; 109 return skip; 110 } 111 112 //----------------------------------------------------------------------- 113 /** 114 * The number of bytes that have passed through this stream. 115 * <p> 116 * NOTE: From v1.3 this method throws an ArithmeticException if the 117 * count is greater than can be expressed by an <code>int</code>. 118 * See {@link #getByteCount()} for a method using a <code>long</code>. 119 * 120 * @return the number of bytes accumulated 121 * @throws ArithmeticException if the byte count is too large 122 */ 123 public synchronized int getCount() { 124 long result = getByteCount(); 125 if (result > Integer.MAX_VALUE) { 126 throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); 127 } 128 return (int) result; 129 } 130 131 /** 132 * Set the byte count back to 0. 133 * <p> 134 * NOTE: From v1.3 this method throws an ArithmeticException if the 135 * count is greater than can be expressed by an <code>int</code>. 136 * See {@link #resetByteCount()} for a method using a <code>long</code>. 137 * 138 * @return the count previous to resetting 139 * @throws ArithmeticException if the byte count is too large 140 */ 141 public synchronized int resetCount() { 142 long result = resetByteCount(); 143 if (result > Integer.MAX_VALUE) { 144 throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); 145 } 146 return (int) result; 147 } 148 149 /** 150 * The number of bytes that have passed through this stream. 151 * <p> 152 * NOTE: This method is an alternative for <code>getCount()</code> 153 * and was added because that method returns an integer which will 154 * result in incorrect count for files over 2GB. 155 * 156 * @return the number of bytes accumulated 157 * @since Commons IO 1.3 158 */ 159 public synchronized long getByteCount() { 160 return this.count; 161 } 162 163 /** 164 * Set the byte count back to 0. 165 * <p> 166 * NOTE: This method is an alternative for <code>resetCount()</code> 167 * and was added because that method returns an integer which will 168 * result in incorrect count for files over 2GB. 169 * 170 * @return the count previous to resetting 171 * @since Commons IO 1.3 172 */ 173 public synchronized long resetByteCount() { 174 long tmp = this.count; 175 this.count = 0; 176 return tmp; 177 } 178 179 }