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 018package org.apache.commons.io.file; 019 020import java.math.BigInteger; 021import java.util.Objects; 022 023/** 024 * Provides counters for files, directories, and sizes, as a visit proceeds. 025 * 026 * @since 2.7 027 */ 028public class Counters { 029 030 /** 031 * Counts files, directories, and sizes, as a visit proceeds. 032 */ 033 private static class AbstractPathCounters implements PathCounters { 034 035 private final Counter byteCounter; 036 private final Counter directoryCounter; 037 private final Counter fileCounter; 038 039 /** 040 * Constructs a new instance. 041 * 042 * @param byteCounter the byte counter. 043 * @param directoryCounter the directory counter. 044 * @param fileCounter the file counter. 045 */ 046 protected AbstractPathCounters(final Counter byteCounter, final Counter directoryCounter, 047 final Counter fileCounter) { 048 this.byteCounter = byteCounter; 049 this.directoryCounter = directoryCounter; 050 this.fileCounter = fileCounter; 051 } 052 053 @Override 054 public boolean equals(final Object obj) { 055 if (this == obj) { 056 return true; 057 } 058 if (!(obj instanceof AbstractPathCounters)) { 059 return false; 060 } 061 final AbstractPathCounters other = (AbstractPathCounters) obj; 062 return Objects.equals(byteCounter, other.byteCounter) 063 && Objects.equals(directoryCounter, other.directoryCounter) 064 && Objects.equals(fileCounter, other.fileCounter); 065 } 066 067 @Override 068 public Counter getByteCounter() { 069 return byteCounter; 070 } 071 072 @Override 073 public Counter getDirectoryCounter() { 074 return directoryCounter; 075 } 076 077 /** 078 * Gets the count of visited files. 079 * 080 * @return the byte count of visited files. 081 */ 082 @Override 083 public Counter getFileCounter() { 084 return this.fileCounter; 085 } 086 087 @Override 088 public int hashCode() { 089 return Objects.hash(byteCounter, directoryCounter, fileCounter); 090 } 091 092 @Override 093 public void reset() { 094 byteCounter.reset(); 095 directoryCounter.reset(); 096 fileCounter.reset(); 097 } 098 099 @Override 100 public String toString() { 101 return String.format("%,d files, %,d directories, %,d bytes", Long.valueOf(fileCounter.get()), 102 Long.valueOf(directoryCounter.get()), Long.valueOf(byteCounter.get())); 103 } 104 105 } 106 107 /** 108 * Counts using a BigInteger number. 109 */ 110 private static final class BigIntegerCounter implements Counter { 111 112 private BigInteger value = BigInteger.ZERO; 113 114 @Override 115 public void add(final long val) { 116 value = value.add(BigInteger.valueOf(val)); 117 118 } 119 120 @Override 121 public boolean equals(final Object obj) { 122 if (this == obj) { 123 return true; 124 } 125 if (!(obj instanceof Counter)) { 126 return false; 127 } 128 final Counter other = (Counter) obj; 129 return Objects.equals(value, other.getBigInteger()); 130 } 131 132 @Override 133 public long get() { 134 return value.longValueExact(); 135 } 136 137 @Override 138 public BigInteger getBigInteger() { 139 return value; 140 } 141 142 @Override 143 public Long getLong() { 144 return Long.valueOf(value.longValueExact()); 145 } 146 147 @Override 148 public int hashCode() { 149 return Objects.hash(value); 150 } 151 152 @Override 153 public void increment() { 154 value = value.add(BigInteger.ONE); 155 } 156 157 @Override 158 public String toString() { 159 return value.toString(); 160 } 161 162 @Override 163 public void reset() { 164 value = BigInteger.ZERO; 165 } 166 } 167 168 /** 169 * Counts files, directories, and sizes, as a visit proceeds, using BigInteger numbers. 170 */ 171 private final static class BigIntegerPathCounters extends AbstractPathCounters { 172 173 /** 174 * Constructs a new initialized instance. 175 */ 176 protected BigIntegerPathCounters() { 177 super(Counters.bigIntegerCounter(), Counters.bigIntegerCounter(), Counters.bigIntegerCounter()); 178 } 179 180 } 181 182 /** 183 * Counts using a number. 184 */ 185 public interface Counter { 186 187 /** 188 * Adds the given number to this counter. 189 * 190 * @param val the value to add. 191 */ 192 void add(long val); 193 194 /** 195 * Gets the counter as a long. 196 * 197 * @return the counter as a long. 198 */ 199 long get(); 200 201 /** 202 * Gets the counter as a BigInteger. 203 * 204 * @return the counter as a BigInteger. 205 */ 206 BigInteger getBigInteger(); 207 208 /** 209 * Gets the counter as a Long. 210 * 211 * @return the counter as a Long. 212 */ 213 Long getLong(); 214 215 /** 216 * Adds one to this counter. 217 */ 218 void increment(); 219 220 /** 221 * Resets this count to 0. 222 */ 223 default void reset() { 224 // binary compat, do nothing 225 } 226 227 } 228 229 /** 230 * Counts using a long number. 231 */ 232 private final static class LongCounter implements Counter { 233 234 private long value; 235 236 @Override 237 public void add(final long add) { 238 value += add; 239 240 } 241 242 @Override 243 public boolean equals(final Object obj) { 244 if (this == obj) { 245 return true; 246 } 247 if (!(obj instanceof Counter)) { 248 return false; 249 } 250 final Counter other = (Counter) obj; 251 return value == other.get(); 252 } 253 254 @Override 255 public long get() { 256 return value; 257 } 258 259 @Override 260 public BigInteger getBigInteger() { 261 return BigInteger.valueOf(value); 262 } 263 264 @Override 265 public Long getLong() { 266 return Long.valueOf(value); 267 } 268 269 @Override 270 public int hashCode() { 271 return Objects.hash(value); 272 } 273 274 @Override 275 public void increment() { 276 value++; 277 } 278 279 @Override 280 public String toString() { 281 return Long.toString(value); 282 } 283 284 @Override 285 public void reset() { 286 value = 0L; 287 } 288 } 289 290 /** 291 * Counts files, directories, and sizes, as a visit proceeds, using long numbers. 292 */ 293 private final static class LongPathCounters extends AbstractPathCounters { 294 295 /** 296 * Constructs a new initialized instance. 297 */ 298 protected LongPathCounters() { 299 super(Counters.longCounter(), Counters.longCounter(), Counters.longCounter()); 300 } 301 302 } 303 304 /** 305 * Counts nothing. 306 */ 307 private final static class NoopCounter implements Counter { 308 309 static final NoopCounter INSTANCE = new NoopCounter(); 310 311 @Override 312 public void add(final long add) { 313 // noop 314 } 315 316 @Override 317 public long get() { 318 return 0; 319 } 320 321 @Override 322 public BigInteger getBigInteger() { 323 return BigInteger.ZERO; 324 } 325 326 @Override 327 public Long getLong() { 328 return 0L; 329 } 330 331 @Override 332 public void increment() { 333 // noop 334 } 335 336 } 337 338 /** 339 * Counts nothing. 340 */ 341 private static final class NoopPathCounters extends AbstractPathCounters { 342 343 static final NoopPathCounters INSTANCE = new NoopPathCounters(); 344 345 /** 346 * Constructs a new initialized instance. 347 */ 348 private NoopPathCounters() { 349 super(Counters.noopCounter(), Counters.noopCounter(), Counters.noopCounter()); 350 } 351 352 } 353 354 /** 355 * Counts files, directories, and sizes, as a visit proceeds. 356 */ 357 public interface PathCounters { 358 359 /** 360 * Gets the byte counter. 361 * 362 * @return the byte counter. 363 */ 364 Counter getByteCounter(); 365 366 /** 367 * Gets the directory counter. 368 * 369 * @return the directory counter. 370 */ 371 Counter getDirectoryCounter(); 372 373 /** 374 * Gets the file counter. 375 * 376 * @return the file counter. 377 */ 378 Counter getFileCounter(); 379 380 /** 381 * Resets the counts to 0. 382 */ 383 default void reset() { 384 // binary compat, do nothing 385 } 386 387 } 388 389 /** 390 * Returns a new BigInteger Counter. 391 * 392 * @return a new BigInteger Counter. 393 */ 394 public static Counter bigIntegerCounter() { 395 return new BigIntegerCounter(); 396 } 397 398 /** 399 * Returns a new BigInteger PathCounters. 400 * 401 * @return a new BigInteger PathCounters. 402 */ 403 public static PathCounters bigIntegerPathCounters() { 404 return new BigIntegerPathCounters(); 405 } 406 407 /** 408 * Returns a new long Counter. 409 * 410 * @return a new long Counter. 411 */ 412 public static Counter longCounter() { 413 return new LongCounter(); 414 } 415 416 /** 417 * Returns a new BigInteger PathCounters. 418 * 419 * @return a new BigInteger PathCounters. 420 */ 421 public static PathCounters longPathCounters() { 422 return new LongPathCounters(); 423 } 424 425 /** 426 * Returns the NOOP Counter. 427 * 428 * @return the NOOP Counter. 429 * @since 2.9.0 430 */ 431 public static Counter noopCounter() { 432 return NoopCounter.INSTANCE; 433 } 434 435 /** 436 * Returns the NOOP PathCounters. 437 * 438 * @return the NOOP PathCounters. 439 * @since 2.9.0 440 */ 441 public static PathCounters noopPathCounters() { 442 return NoopPathCounters.INSTANCE; 443 } 444}