View Javadoc
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  
18  package org.apache.commons.io.file;
19  
20  import java.io.IOException;
21  import java.nio.file.FileVisitResult;
22  import java.nio.file.Path;
23  import java.nio.file.attribute.BasicFileAttributes;
24  import java.util.ArrayList;
25  import java.util.Comparator;
26  import java.util.List;
27  import java.util.Objects;
28  
29  import org.apache.commons.io.file.Counters.PathCounters;
30  import org.apache.commons.io.function.IOBiFunction;
31  
32  /**
33   * Accumulates normalized paths during visitation.
34   * <p>
35   * Use with care on large file trees as each visited Path element is remembered.
36   * </p>
37   * <h2>Example</h2>
38   *
39   * <pre>
40   * Path dir = PathUtils.current();
41   * // We are interested in files older than one day
42   * Instant cutoff = Instant.now().minus(Duration.ofDays(1));
43   * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
44   * //
45   * // Walk one directory
46   * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
47   * System.out.println(visitor.getPathCounters());
48   * System.out.println(visitor.getFileList());
49   * //
50   * visitor.getPathCounters().reset();
51   * //
52   * // Walk directory tree
53   * Files.walkFileTree(dir, visitor);
54   * System.out.println(visitor.getPathCounters());
55   * System.out.println(visitor.getDirList());
56   * System.out.println(visitor.getFileList());
57   * </pre>
58   *
59   * @since 2.7
60   */
61  public class AccumulatorPathVisitor extends CountingPathVisitor {
62  
63      /**
64       * Builds instances of {@link AccumulatorPathVisitor}.
65       *
66       * @since 2.19.0
67       */
68      public static class Builder extends AbstractBuilder<AccumulatorPathVisitor, Builder> {
69  
70          /**
71           * Constructs a new builder.
72           */
73          public Builder() {
74              // empty.
75          }
76  
77          @Override
78          public AccumulatorPathVisitor get() {
79              return new AccumulatorPathVisitor(this);
80          }
81  
82      }
83  
84      /**
85       * Builds instances of {@link AccumulatorPathVisitor}.
86       *
87       * @return a new builder.
88       * @since 2.19.0
89       */
90      public static Builder builder() {
91          return new Builder();
92      }
93  
94      /**
95       * Constructs a new instance configured with a BigInteger {@link PathCounters}.
96       *
97       * @return a new instance configured with a BigInteger {@link PathCounters}.
98       * @see #builder()
99       * @see Builder
100      */
101     public static AccumulatorPathVisitor withBigIntegerCounters() {
102         return builder().setPathCounters(Counters.bigIntegerPathCounters()).get();
103     }
104 
105     /**
106      * Constructs a new instance configured with a BigInteger {@link PathCounters}.
107      *
108      * @param fileFilter Filters files to accumulate and count.
109      * @param dirFilter Filters directories to accumulate and count.
110      * @return a new instance configured with a long {@link PathCounters}.
111      * @see #builder()
112      * @see Builder
113      * @since 2.9.0
114      */
115     public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
116         return builder().setPathCounters(Counters.bigIntegerPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
117     }
118 
119     /**
120      * Constructs a new instance configured with a long {@link PathCounters}.
121      *
122      * @return a new instance configured with a long {@link PathCounters}.
123      * @see #builder()
124      * @see Builder
125      */
126     public static AccumulatorPathVisitor withLongCounters() {
127         return builder().setPathCounters(Counters.longPathCounters()).get();
128     }
129 
130     /**
131      * Constructs a new instance configured with a long {@link PathCounters}.
132      *
133      * @param fileFilter Filters files to accumulate and count.
134      * @param dirFilter Filters directories to accumulate and count.
135      * @return a new instance configured with a long {@link PathCounters}.
136      * @see #builder()
137      * @see Builder
138      * @since 2.9.0
139      */
140     public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
141         return builder().setPathCounters(Counters.longPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
142     }
143 
144     private final List<Path> dirList = new ArrayList<>();
145 
146     private final List<Path> fileList = new ArrayList<>();
147 
148     /**
149      * Constructs a new instance with a noop path counter.
150      *
151      * @since 2.9.0
152      * @deprecated Use {@link #builder()}.
153      */
154     @Deprecated
155     public AccumulatorPathVisitor() {
156         super(Counters.noopPathCounters());
157     }
158 
159     private AccumulatorPathVisitor(final Builder builder) {
160         super(builder);
161     }
162 
163     /**
164      * Constructs a new instance that counts file system elements.
165      *
166      * @param pathCounter How to count path visits.
167      * @deprecated Use {@link #builder()}.
168      */
169     @Deprecated
170     public AccumulatorPathVisitor(final PathCounters pathCounter) {
171         super(pathCounter);
172     }
173 
174     /**
175      * Constructs a new instance.
176      *
177      * @param pathCounter How to count path visits.
178      * @param fileFilter Filters which files to count.
179      * @param dirFilter Filters which directories to count.
180      * @since 2.9.0
181      * @deprecated Use {@link #builder()}.
182      */
183     @Deprecated
184     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) {
185         super(pathCounter, fileFilter, dirFilter);
186     }
187 
188     /**
189      * Constructs a new instance.
190      *
191      * @param pathCounter How to count path visits.
192      * @param fileFilter Filters which files to count.
193      * @param dirFilter Filters which directories to count.
194      * @param visitFileFailed Called on {@link #visitFileFailed(Path, IOException)}.
195      * @since 2.12.0
196      * @deprecated Use {@link #builder()}.
197      */
198     @Deprecated
199     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter,
200         final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed) {
201         super(pathCounter, fileFilter, dirFilter, visitFileFailed);
202     }
203 
204     private void add(final List<Path> list, final Path dir) {
205         list.add(dir.normalize());
206     }
207 
208     @Override
209     public boolean equals(final Object obj) {
210         if (this == obj) {
211             return true;
212         }
213         if (!super.equals(obj)) {
214             return false;
215         }
216         if (!(obj instanceof AccumulatorPathVisitor)) {
217             return false;
218         }
219         final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj;
220         return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList);
221     }
222 
223     /**
224      * Gets a copy of the list of visited directories.
225      *
226      * @return a copy of the list of visited directories.
227      */
228     public List<Path> getDirList() {
229         return new ArrayList<>(dirList);
230     }
231 
232     /**
233      * Gets a copy of the list of visited files.
234      *
235      * @return a copy of the list of visited files.
236      */
237     public List<Path> getFileList() {
238         return new ArrayList<>(fileList);
239     }
240 
241     @Override
242     public int hashCode() {
243         final int prime = 31;
244         int result = super.hashCode();
245         result = prime * result + Objects.hash(dirList, fileList);
246         return result;
247     }
248 
249     /**
250      * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
251      * sorting the result.
252      *
253      * @param parent A parent path
254      * @param sort Whether to sort
255      * @param comparator How to sort, null uses default sorting.
256      * @return A new list
257      */
258     public List<Path> relativizeDirectories(final Path parent, final boolean sort,
259         final Comparator<? super Path> comparator) {
260         return PathUtils.relativize(getDirList(), parent, sort, comparator);
261     }
262 
263     /**
264      * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
265      * sorting the result.
266      *
267      * @param parent A parent path
268      * @param sort Whether to sort
269      * @param comparator How to sort, null uses default sorting.
270      * @return A new list
271      */
272     public List<Path> relativizeFiles(final Path parent, final boolean sort,
273         final Comparator<? super Path> comparator) {
274         return PathUtils.relativize(getFileList(), parent, sort, comparator);
275     }
276 
277     @Override
278     protected void updateDirCounter(final Path dir, final IOException exc) {
279         super.updateDirCounter(dir, exc);
280         add(dirList, dir);
281     }
282 
283     @Override
284     protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) {
285         super.updateFileCounters(file, attributes);
286         add(fileList, file);
287     }
288 
289 }