• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.math.BigInteger;
22 import java.nio.file.FileVisitResult;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.nio.file.attribute.BasicFileAttributes;
26 import java.util.Objects;
27 
28 import org.apache.commons.io.file.Counters.PathCounters;
29 import org.apache.commons.io.filefilter.IOFileFilter;
30 import org.apache.commons.io.filefilter.SymbolicLinkFileFilter;
31 import org.apache.commons.io.filefilter.TrueFileFilter;
32 import org.apache.commons.io.function.IOBiFunction;
33 
34 /**
35  * Counts files, directories, and sizes, as a visit proceeds.
36  *
37  * @since 2.7
38  */
39 public class CountingPathVisitor extends SimplePathVisitor {
40 
41     static final String[] EMPTY_STRING_ARRAY = {};
42 
defaultDirFilter()43     static IOFileFilter defaultDirFilter() {
44         return TrueFileFilter.INSTANCE;
45     }
46 
defaultFileFilter()47     static IOFileFilter defaultFileFilter() {
48         return new SymbolicLinkFileFilter(FileVisitResult.TERMINATE, FileVisitResult.CONTINUE);
49     }
50 
51     /**
52      * Creates a new instance configured with a {@link BigInteger} {@link PathCounters}.
53      *
54      * @return a new instance configured with a {@link BigInteger} {@link PathCounters}.
55      */
withBigIntegerCounters()56     public static CountingPathVisitor withBigIntegerCounters() {
57         return new CountingPathVisitor(Counters.bigIntegerPathCounters());
58     }
59 
60     /**
61      * Creates a new instance configured with a {@code long} {@link PathCounters}.
62      *
63      * @return a new instance configured with a {@code long} {@link PathCounters}.
64      */
withLongCounters()65     public static CountingPathVisitor withLongCounters() {
66         return new CountingPathVisitor(Counters.longPathCounters());
67     }
68 
69     private final PathCounters pathCounters;
70     private final PathFilter fileFilter;
71     private final PathFilter dirFilter;
72 
73     /**
74      * Constructs a new instance.
75      *
76      * @param pathCounter How to count path visits.
77      */
CountingPathVisitor(final PathCounters pathCounter)78     public CountingPathVisitor(final PathCounters pathCounter) {
79         this(pathCounter, defaultFileFilter(), defaultDirFilter());
80     }
81 
82     /**
83      * Constructs a new instance.
84      *
85      * @param pathCounter How to count path visits.
86      * @param fileFilter Filters which files to count.
87      * @param dirFilter Filters which directories to count.
88      * @since 2.9.0
89      */
CountingPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter)90     public CountingPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) {
91         this.pathCounters = Objects.requireNonNull(pathCounter, "pathCounter");
92         this.fileFilter = Objects.requireNonNull(fileFilter, "fileFilter");
93         this.dirFilter = Objects.requireNonNull(dirFilter, "dirFilter");
94     }
95 
96     /**
97      * Constructs a new instance.
98      *
99      * @param pathCounter How to count path visits.
100      * @param fileFilter Filters which files to count.
101      * @param dirFilter Filters which directories to count.
102      * @param visitFileFailed Called on {@link #visitFileFailed(Path, IOException)}.
103      * @since 2.12.0
104      */
CountingPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter, final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed)105     public CountingPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter,
106         final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed) {
107         super(visitFileFailed);
108         this.pathCounters = Objects.requireNonNull(pathCounter, "pathCounter");
109         this.fileFilter = Objects.requireNonNull(fileFilter, "fileFilter");
110         this.dirFilter = Objects.requireNonNull(dirFilter, "dirFilter");
111     }
112 
113     @Override
equals(final Object obj)114     public boolean equals(final Object obj) {
115         if (this == obj) {
116             return true;
117         }
118         if (!(obj instanceof CountingPathVisitor)) {
119             return false;
120         }
121         final CountingPathVisitor other = (CountingPathVisitor) obj;
122         return Objects.equals(pathCounters, other.pathCounters);
123     }
124 
125     /**
126      * Gets the visitation counts.
127      *
128      * @return the visitation counts.
129      */
getPathCounters()130     public PathCounters getPathCounters() {
131         return pathCounters;
132     }
133 
134     @Override
hashCode()135     public int hashCode() {
136         return Objects.hash(pathCounters);
137     }
138 
139     @Override
postVisitDirectory(final Path dir, final IOException exc)140     public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
141         updateDirCounter(dir, exc);
142         return FileVisitResult.CONTINUE;
143     }
144 
145     @Override
preVisitDirectory(final Path dir, final BasicFileAttributes attributes)146     public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attributes) throws IOException {
147         final FileVisitResult accept = dirFilter.accept(dir, attributes);
148         return accept != FileVisitResult.CONTINUE ? FileVisitResult.SKIP_SUBTREE : FileVisitResult.CONTINUE;
149     }
150 
151     @Override
toString()152     public String toString() {
153         return pathCounters.toString();
154     }
155 
156     /**
157      * Updates the counter for visiting the given directory.
158      *
159      * @param dir the visited directory.
160      * @param exc Encountered exception.
161      * @since 2.9.0
162      */
updateDirCounter(final Path dir, final IOException exc)163     protected void updateDirCounter(final Path dir, final IOException exc) {
164         pathCounters.getDirectoryCounter().increment();
165     }
166 
167     /**
168      * Updates the counters for visiting the given file.
169      *
170      * @param file the visited file.
171      * @param attributes the visited file attributes.
172      */
updateFileCounters(final Path file, final BasicFileAttributes attributes)173     protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) {
174         pathCounters.getFileCounter().increment();
175         pathCounters.getByteCounter().add(attributes.size());
176     }
177 
178     @Override
visitFile(final Path file, final BasicFileAttributes attributes)179     public FileVisitResult visitFile(final Path file, final BasicFileAttributes attributes) throws IOException {
180         // Note: A file can be a symbolic link to a directory.
181         if (Files.exists(file) && fileFilter.accept(file, attributes) == FileVisitResult.CONTINUE) {
182             updateFileCounters(file, attributes);
183         }
184         return FileVisitResult.CONTINUE;
185     }
186 
187 }
188