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 name.
33 * <p>
34 * For example, to print all files and directories in the
35 * current directory whose name is {@code Test}:
36 * </p>
37 * <h2>Using Classic IO</h2>
38 * <pre>
39 * File dir = FileUtils.current();
40 * String[] files = dir.list(new NameFileFilter("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 NameFileFilter("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#nameFileFilter(String)
71 * @see FileFilterUtils#nameFileFilter(String, IOCase)
72 */
73 public class NameFileFilter extends AbstractFileFilter implements Serializable {
74
75 private static final long serialVersionUID = 176844364689077340L;
76
77 /** The file names to search for */
78 private final String[] names;
79
80 /** Whether the comparison is case-sensitive. */
81 private final IOCase ioCase;
82
83 /**
84 * Constructs a new case-sensitive name file filter for a list of names.
85 *
86 * @param names the names to allow, must not be null
87 * @throws IllegalArgumentException if the name list is null
88 * @throws ClassCastException if the list does not contain Strings
89 */
90 public NameFileFilter(final List<String> names) {
91 this(names, null);
92 }
93
94 /**
95 * Constructs a new name file filter for a list of names specifying case-sensitivity.
96 *
97 * @param names the names to allow, must not be null
98 * @param ioCase how to handle case sensitivity, null means case-sensitive
99 * @throws NullPointerException if the name list is null
100 * @throws ClassCastException if the list does not contain Strings
101 */
102 public NameFileFilter(final List<String> names, final IOCase ioCase) {
103 Objects.requireNonNull(names, "names");
104 this.names = names.toArray(EMPTY_STRING_ARRAY);
105 this.ioCase = toIOCase(ioCase);
106 }
107
108 /**
109 * Constructs a new case-sensitive name file filter for a single name.
110 *
111 * @param name the name to allow, must not be null
112 * @throws IllegalArgumentException if the name is null
113 */
114 public NameFileFilter(final String name) {
115 this(name, IOCase.SENSITIVE);
116 }
117
118 /**
119 * Constructs a new case-sensitive name file filter for an array of names.
120 * <p>
121 * The array is not cloned, so could be changed after constructing the
122 * instance. This would be inadvisable however.
123 * </p>
124 *
125 * @param names the names to allow, must not be null
126 * @throws IllegalArgumentException if the names array is null
127 */
128 public NameFileFilter(final String... names) {
129 this(names, IOCase.SENSITIVE);
130 }
131
132 /**
133 * Constructs a new name file filter specifying case-sensitivity.
134 *
135 * @param name the name to allow, must not be null
136 * @param ioCase how to handle case sensitivity, null means case-sensitive
137 * @throws NullPointerException if the name is null
138 */
139 public NameFileFilter(final String name, final IOCase ioCase) {
140 Objects.requireNonNull(name, "name");
141 this.names = new String[] {name};
142 this.ioCase = toIOCase(ioCase);
143 }
144
145 /**
146 * Constructs a new name file filter for an array of names specifying case-sensitivity.
147 *
148 * @param names the names to allow, must not be null
149 * @param ioCase how to handle case sensitivity, null means case-sensitive
150 * @throws NullPointerException if the names array is null
151 */
152 public NameFileFilter(final String[] names, final IOCase ioCase) {
153 Objects.requireNonNull(names, "names");
154 this.names = names.clone();
155 this.ioCase = toIOCase(ioCase);
156 }
157
158 /**
159 * Tests to see if the file name matches.
160 *
161 * @param file the File to check
162 * @return true if the file name matches
163 */
164 @Override
165 public boolean accept(final File file) {
166 return file != null && acceptBaseName(file.getName());
167 }
168
169 /**
170 * Tests to see if the file name matches.
171 *
172 * @param dir the File directory (ignored)
173 * @param name the file name
174 * @return true if the file name matches
175 */
176 @Override
177 public boolean accept(final File dir, final String name) {
178 return acceptBaseName(name);
179 }
180
181 /**
182 * Checks to see if the file name matches.
183 *
184 * @param path the File to check
185 * @param attributes the path's basic attributes (may be null).
186 * @return true if the file name matches
187 * @since 2.9.0
188 */
189 @Override
190 public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) {
191 return toFileVisitResult(acceptBaseName(PathUtils.getFileNameString(path)));
192 }
193
194 private boolean acceptBaseName(final String baseName) {
195 return Stream.of(names).anyMatch(testName -> ioCase.checkEquals(baseName, testName));
196 }
197
198 private IOCase toIOCase(final IOCase ioCase) {
199 return IOCase.value(ioCase, IOCase.SENSITIVE);
200 }
201
202 /**
203 * Provide a String representation of this file filter.
204 *
205 * @return a String representation
206 */
207 @Override
208 public String toString() {
209 final StringBuilder buffer = new StringBuilder();
210 buffer.append(super.toString());
211 buffer.append("(");
212 append(names, buffer);
213 buffer.append(")");
214 return buffer.toString();
215 }
216
217 }