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.io.IOException; 021import java.nio.file.FileVisitResult; 022import java.nio.file.Path; 023import java.nio.file.attribute.BasicFileAttributes; 024import java.util.ArrayList; 025import java.util.Comparator; 026import java.util.List; 027import java.util.Objects; 028 029import org.apache.commons.io.file.Counters.PathCounters; 030import org.apache.commons.io.function.IOBiFunction; 031 032/** 033 * Accumulates normalized paths during visitation. 034 * <p> 035 * Use with care on large file trees as each visited Path element is remembered. 036 * </p> 037 * <h2>Example</h2> 038 * 039 * <pre> 040 * Path dir = PathUtils.current(); 041 * // We are interested in files older than one day 042 * Instant cutoff = Instant.now().minus(Duration.ofDays(1)); 043 * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff)); 044 * // 045 * // Walk one directory 046 * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor); 047 * System.out.println(visitor.getPathCounters()); 048 * System.out.println(visitor.getFileList()); 049 * // 050 * visitor.getPathCounters().reset(); 051 * // 052 * // Walk directory tree 053 * Files.walkFileTree(dir, visitor); 054 * System.out.println(visitor.getPathCounters()); 055 * System.out.println(visitor.getDirList()); 056 * System.out.println(visitor.getFileList()); 057 * </pre> 058 * 059 * @since 2.7 060 */ 061public class AccumulatorPathVisitor extends CountingPathVisitor { 062 063 /** 064 * Constructs a new instance configured with a BigInteger {@link PathCounters}. 065 * 066 * @return a new instance configured with a BigInteger {@link PathCounters}. 067 */ 068 public static AccumulatorPathVisitor withBigIntegerCounters() { 069 return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters()); 070 } 071 072 /** 073 * Constructs a new instance configured with a BigInteger {@link PathCounters}. 074 * 075 * @param fileFilter Filters files to accumulate and count. 076 * @param dirFilter Filters directories to accumulate and count. 077 * @return a new instance configured with a long {@link PathCounters}. 078 * @since 2.9.0 079 */ 080 public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter, 081 final PathFilter dirFilter) { 082 return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters(), fileFilter, dirFilter); 083 } 084 085 /** 086 * Constructs a new instance configured with a long {@link PathCounters}. 087 * 088 * @return a new instance configured with a long {@link PathCounters}. 089 */ 090 public static AccumulatorPathVisitor withLongCounters() { 091 return new AccumulatorPathVisitor(Counters.longPathCounters()); 092 } 093 094 /** 095 * Constructs a new instance configured with a long {@link PathCounters}. 096 * 097 * @param fileFilter Filters files to accumulate and count. 098 * @param dirFilter Filters directories to accumulate and count. 099 * @return a new instance configured with a long {@link PathCounters}. 100 * @since 2.9.0 101 */ 102 public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) { 103 return new AccumulatorPathVisitor(Counters.longPathCounters(), fileFilter, dirFilter); 104 } 105 106 private final List<Path> dirList = new ArrayList<>(); 107 108 private final List<Path> fileList = new ArrayList<>(); 109 110 /** 111 * Constructs a new instance. 112 * 113 * @since 2.9.0 114 */ 115 public AccumulatorPathVisitor() { 116 super(Counters.noopPathCounters()); 117 } 118 119 /** 120 * Constructs a new instance that counts file system elements. 121 * 122 * @param pathCounter How to count path visits. 123 */ 124 public AccumulatorPathVisitor(final PathCounters pathCounter) { 125 super(pathCounter); 126 } 127 128 /** 129 * Constructs a new instance. 130 * 131 * @param pathCounter How to count path visits. 132 * @param fileFilter Filters which files to count. 133 * @param dirFilter Filters which directories to count. 134 * @since 2.9.0 135 */ 136 public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) { 137 super(pathCounter, fileFilter, dirFilter); 138 } 139 140 /** 141 * Constructs a new instance. 142 * 143 * @param pathCounter How to count path visits. 144 * @param fileFilter Filters which files to count. 145 * @param dirFilter Filters which directories to count. 146 * @param visitFileFailed Called on {@link #visitFileFailed(Path, IOException)}. 147 * @since 2.12.0 148 */ 149 public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter, 150 final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed) { 151 super(pathCounter, fileFilter, dirFilter, visitFileFailed); 152 } 153 154 private void add(final List<Path> list, final Path dir) { 155 list.add(dir.normalize()); 156 } 157 158 @Override 159 public boolean equals(final Object obj) { 160 if (this == obj) { 161 return true; 162 } 163 if (!super.equals(obj)) { 164 return false; 165 } 166 if (!(obj instanceof AccumulatorPathVisitor)) { 167 return false; 168 } 169 final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj; 170 return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList); 171 } 172 173 /** 174 * Gets a copy of the list of visited directories. 175 * 176 * @return a copy of the list of visited directories. 177 */ 178 public List<Path> getDirList() { 179 return new ArrayList<>(dirList); 180 } 181 182 /** 183 * Gets a copy of the list of visited files. 184 * 185 * @return a copy of the list of visited files. 186 */ 187 public List<Path> getFileList() { 188 return new ArrayList<>(fileList); 189 } 190 191 @Override 192 public int hashCode() { 193 final int prime = 31; 194 int result = super.hashCode(); 195 result = prime * result + Objects.hash(dirList, fileList); 196 return result; 197 } 198 199 /** 200 * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally 201 * sorting the result. 202 * 203 * @param parent A parent path 204 * @param sort Whether to sort 205 * @param comparator How to sort, null uses default sorting. 206 * @return A new list 207 */ 208 public List<Path> relativizeDirectories(final Path parent, final boolean sort, 209 final Comparator<? super Path> comparator) { 210 return PathUtils.relativize(getDirList(), parent, sort, comparator); 211 } 212 213 /** 214 * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally 215 * sorting the result. 216 * 217 * @param parent A parent path 218 * @param sort Whether to sort 219 * @param comparator How to sort, null uses default sorting. 220 * @return A new list 221 */ 222 public List<Path> relativizeFiles(final Path parent, final boolean sort, 223 final Comparator<? super Path> comparator) { 224 return PathUtils.relativize(getFileList(), parent, sort, comparator); 225 } 226 227 @Override 228 protected void updateDirCounter(final Path dir, final IOException exc) { 229 super.updateDirCounter(dir, exc); 230 add(dirList, dir); 231 } 232 233 @Override 234 protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) { 235 super.updateFileCounters(file, attributes); 236 add(fileList, file); 237 } 238 239}