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 * https://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 package org.apache.commons.io.filefilter;
18
19 import java.io.File;
20 import java.io.Serializable;
21 import java.nio.file.FileVisitResult;
22 import java.nio.file.Path;
23 import java.nio.file.attribute.BasicFileAttributes;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.stream.Stream;
27
28 import org.apache.commons.io.IOCase;
29 import org.apache.commons.io.file.PathUtils;
30
31 /**
32 * Filters file names for a certain prefix.
33 * <p>
34 * For example, to print all files and directories in the
35 * current directory whose name starts with {@code Test}:
36 * </p>
37 * <h2>Using Classic IO</h2>
38 * <pre>
39 * File dir = FileUtils.current();
40 * String[] files = dir.list(new PrefixFileFilter("Test"));
41 * for (String file : files) {
42 * System.out.println(file);
43 * }
44 * </pre>
45 *
46 * <h2>Using NIO</h2>
47 * <pre>
48 * final Path dir = PathUtils.current();
49 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new PrefixFileFilter("Test"));
50 * //
51 * // Walk one directory
52 * Files.<strong>walkFileTree</strong>(dir, Collections.emptySet(), 1, visitor);
53 * System.out.println(visitor.getPathCounters());
54 * System.out.println(visitor.getFileList());
55 * //
56 * visitor.getPathCounters().reset();
57 * //
58 * // Walk directory tree
59 * Files.<strong>walkFileTree</strong>(dir, visitor);
60 * System.out.println(visitor.getPathCounters());
61 * System.out.println(visitor.getDirList());
62 * System.out.println(visitor.getFileList());
63 * </pre>
64 * <h2>Deprecating Serialization</h2>
65 * <p>
66 * <em>Serialization is deprecated and will be removed in 3.0.</em>
67 * </p>
68 *
69 * @since 1.0
70 * @see FileFilterUtils#prefixFileFilter(String)
71 * @see FileFilterUtils#prefixFileFilter(String, IOCase)
72 */
73 public class PrefixFileFilter extends AbstractFileFilter implements Serializable {
74
75 private static final long serialVersionUID = 8533897440809599867L;
76
77 /** The file name prefixes to search for */
78 private final String[] prefixes;
79
80 /** Whether the comparison is case-sensitive. */
81 private final IOCase isCase;
82
83 /**
84 * Constructs a new Prefix file filter for a list of prefixes.
85 *
86 * @param prefixes the prefixes to allow, must not be null.
87 * @throws NullPointerException if the prefix list is null.
88 * @throws ClassCastException if the list does not contain Strings.
89 */
90 public PrefixFileFilter(final List<String> prefixes) {
91 this(prefixes, IOCase.SENSITIVE);
92 }
93
94 /**
95 * Constructs a new Prefix file filter for a list of prefixes
96 * specifying case-sensitivity.
97 *
98 * @param prefixes the prefixes to allow, must not be null.
99 * @param ioCase how to handle case sensitivity, null means case-sensitive.
100 * @throws NullPointerException if the prefix list is null.
101 * @throws ClassCastException if the list does not contain Strings.
102 * @since 1.4
103 */
104 public PrefixFileFilter(final List<String> prefixes, final IOCase ioCase) {
105 Objects.requireNonNull(prefixes, "prefixes");
106 this.prefixes = prefixes.toArray(EMPTY_STRING_ARRAY);
107 this.isCase = IOCase.value(ioCase, IOCase.SENSITIVE);
108 }
109
110 /**
111 * Constructs a new Prefix file filter for a single prefix.
112 *
113 * @param prefix the prefix to allow, must not be null.
114 * @throws IllegalArgumentException if the prefix is null.
115 */
116 public PrefixFileFilter(final String prefix) {
117 this(prefix, IOCase.SENSITIVE);
118 }
119
120 /**
121 * Constructs a new Prefix file filter for any of an array of prefixes.
122 * <p>
123 * The array is not cloned, so could be changed after constructing the
124 * instance. This would be inadvisable however.
125 * </p>
126 *
127 * @param prefixes the prefixes to allow, must not be null.
128 * @throws IllegalArgumentException if the prefix array is null.
129 */
130 public PrefixFileFilter(final String... prefixes) {
131 this(prefixes, IOCase.SENSITIVE);
132 }
133
134 /**
135 * Constructs a new Prefix file filter for a single prefix
136 * specifying case-sensitivity.
137 *
138 * @param prefix the prefix to allow, must not be null.
139 * @param ioCase how to handle case sensitivity, null means case-sensitive.
140 * @throws IllegalArgumentException if the prefix is null.
141 * @since 1.4
142 */
143 public PrefixFileFilter(final String prefix, final IOCase ioCase) {
144 Objects.requireNonNull(prefix, "prefix");
145 this.prefixes = new String[] {prefix};
146 this.isCase = IOCase.value(ioCase, IOCase.SENSITIVE);
147 }
148
149 /**
150 * Constructs a new Prefix file filter for any of an array of prefixes
151 * specifying case-sensitivity.
152 *
153 * @param prefixes the prefixes to allow, must not be null.
154 * @param ioCase how to handle case sensitivity, null means case-sensitive.
155 * @throws IllegalArgumentException if the prefix is null.
156 * @since 1.4
157 */
158 public PrefixFileFilter(final String[] prefixes, final IOCase ioCase) {
159 Objects.requireNonNull(prefixes, "prefixes");
160 this.prefixes = prefixes.clone();
161 this.isCase = IOCase.value(ioCase, IOCase.SENSITIVE);
162 }
163
164 /**
165 * Tests to see if the file name starts with the prefix.
166 *
167 * @param file the File to check.
168 * @return true if the file name starts with one of our prefixes.
169 */
170 @Override
171 public boolean accept(final File file) {
172 return accept(file == null ? null : file.getName());
173 }
174
175 /**
176 * Tests to see if the file name starts with the prefix.
177 *
178 * @param file the File directory.
179 * @param name the file name.
180 * @return true if the file name starts with one of our prefixes.
181 */
182 @Override
183 public boolean accept(final File file, final String name) {
184 return accept(name);
185 }
186
187 /**
188 * Tests to see if the file name starts with the prefix.
189 *
190 * @param file the File to check.
191 * @param attributes the path's basic attributes (may be null).
192 * @return true if the file name starts with one of our prefixes.
193 * @since 2.9.0
194 */
195 @Override
196 public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
197 return toFileVisitResult(accept(PathUtils.getFileName(file, Path::toFile)));
198 }
199
200 private boolean accept(final String name) {
201 return Stream.of(prefixes).anyMatch(prefix -> isCase.checkStartsWith(name, prefix));
202 }
203
204 /**
205 * Provides a String representation of this file filter.
206 *
207 * @return a String representation.
208 */
209 @Override
210 public String toString() {
211 final StringBuilder buffer = new StringBuilder();
212 buffer.append(super.toString());
213 buffer.append("(");
214 append(prefixes, buffer);
215 buffer.append(")");
216 return buffer.toString();
217 }
218
219 }