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 dir
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 dir 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       * Constructs a new instance configured with a BigInteger {@link PathCounters}.
65       *
66       * @return a new instance configured with a BigInteger {@link PathCounters}.
67       */
68      public static AccumulatorPathVisitor withBigIntegerCounters() {
69          return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters());
70      }
71  
72      /**
73       * Constructs a new instance configured with a BigInteger {@link PathCounters}.
74       *
75       * @param fileFilter Filters files to accumulate and count.
76       * @param dirFilter Filters directories to accumulate and count.
77       * @return a new instance configured with a long {@link PathCounters}.
78       * @since 2.9.0
79       */
80      public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter,
81          final PathFilter dirFilter) {
82          return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters(), fileFilter, dirFilter);
83      }
84  
85      /**
86       * Constructs a new instance configured with a long {@link PathCounters}.
87       *
88       * @return a new instance configured with a long {@link PathCounters}.
89       */
90      public static AccumulatorPathVisitor withLongCounters() {
91          return new AccumulatorPathVisitor(Counters.longPathCounters());
92      }
93  
94      /**
95       * Constructs a new instance configured with a long {@link PathCounters}.
96       *
97       * @param fileFilter Filters files to accumulate and count.
98       * @param dirFilter Filters directories to accumulate and count.
99       * @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 }