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