001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.filefilter;
018
019import java.io.File;
020import java.io.Serializable;
021import java.nio.file.FileVisitResult;
022import java.nio.file.Path;
023import java.nio.file.attribute.BasicFileAttributes;
024import java.util.List;
025
026import org.apache.commons.io.IOCase;
027
028/**
029 * Filters file names for a certain prefix.
030 * <p>
031 * For example, to print all files and directories in the
032 * current directory whose name starts with {@code Test}:
033 * </p>
034 * <h2>Using Classic IO</h2>
035 * <pre>
036 * File dir = new File(".");
037 * String[] files = dir.list(new PrefixFileFilter("Test"));
038 * for (String file : files) {
039 *     System.out.println(file);
040 * }
041 * </pre>
042 *
043 * <h2>Using NIO</h2>
044 * <pre>
045 * final Path dir = Paths.get("");
046 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new PrefixFileFilter("Test"));
047 * //
048 * // Walk one dir
049 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor);
050 * System.out.println(visitor.getPathCounters());
051 * System.out.println(visitor.getFileList());
052 * //
053 * visitor.getPathCounters().reset();
054 * //
055 * // Walk dir tree
056 * Files.<b>walkFileTree</b>(dir, visitor);
057 * System.out.println(visitor.getPathCounters());
058 * System.out.println(visitor.getDirList());
059 * System.out.println(visitor.getFileList());
060 * </pre>
061 *
062 * @since 1.0
063 * @see FileFilterUtils#prefixFileFilter(String)
064 * @see FileFilterUtils#prefixFileFilter(String, IOCase)
065 */
066public class PrefixFileFilter extends AbstractFileFilter implements Serializable {
067
068    private static final long serialVersionUID = 8533897440809599867L;
069
070    /** The file name prefixes to search for */
071    private final String[] prefixes;
072
073    /** Whether the comparison is case sensitive. */
074    private final IOCase caseSensitivity;
075
076    /**
077     * Constructs a new Prefix file filter for a list of prefixes.
078     *
079     * @param prefixes  the prefixes to allow, must not be null
080     * @throws IllegalArgumentException if the prefix list is null
081     * @throws ClassCastException if the list does not contain Strings
082     */
083    public PrefixFileFilter(final List<String> prefixes) {
084        this(prefixes, IOCase.SENSITIVE);
085    }
086
087    /**
088     * Constructs a new Prefix file filter for a list of prefixes
089     * specifying case-sensitivity.
090     *
091     * @param prefixes  the prefixes to allow, must not be null
092     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
093     * @throws IllegalArgumentException if the prefix list is null
094     * @throws ClassCastException if the list does not contain Strings
095     * @since 1.4
096     */
097    public PrefixFileFilter(final List<String> prefixes, final IOCase caseSensitivity) {
098        if (prefixes == null) {
099            throw new IllegalArgumentException("The list of prefixes must not be null");
100        }
101        this.prefixes = prefixes.toArray(EMPTY_STRING_ARRAY);
102        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
103    }
104
105    /**
106     * Constructs a new Prefix file filter for a single prefix.
107     *
108     * @param prefix  the prefix to allow, must not be null
109     * @throws IllegalArgumentException if the prefix is null
110     */
111    public PrefixFileFilter(final String prefix) {
112        this(prefix, IOCase.SENSITIVE);
113    }
114
115    /**
116     * Constructs a new Prefix file filter for any of an array of prefixes.
117     * <p>
118     * The array is not cloned, so could be changed after constructing the
119     * instance. This would be inadvisable however.
120     *
121     * @param prefixes  the prefixes to allow, must not be null
122     * @throws IllegalArgumentException if the prefix array is null
123     */
124    public PrefixFileFilter(final String... prefixes) {
125        this(prefixes, IOCase.SENSITIVE);
126    }
127
128    /**
129     * Constructs a new Prefix file filter for a single prefix
130     * specifying case-sensitivity.
131     *
132     * @param prefix  the prefix to allow, must not be null
133     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
134     * @throws IllegalArgumentException if the prefix is null
135     * @since 1.4
136     */
137    public PrefixFileFilter(final String prefix, final IOCase caseSensitivity) {
138        if (prefix == null) {
139            throw new IllegalArgumentException("The prefix must not be null");
140        }
141        this.prefixes = new String[] {prefix};
142        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
143    }
144
145    /**
146     * Constructs a new Prefix file filter for any of an array of prefixes
147     * specifying case-sensitivity.
148     *
149     * @param prefixes  the prefixes to allow, must not be null
150     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
151     * @throws IllegalArgumentException if the prefix is null
152     * @since 1.4
153     */
154    public PrefixFileFilter(final String[] prefixes, final IOCase caseSensitivity) {
155        if (prefixes == null) {
156            throw new IllegalArgumentException("The array of prefixes must not be null");
157        }
158        this.prefixes = new String[prefixes.length];
159        System.arraycopy(prefixes, 0, this.prefixes, 0, prefixes.length);
160        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
161    }
162
163    /**
164     * Checks to see if the file name starts with the prefix.
165     *
166     * @param file  the File to check
167     * @return true if the file name starts with one of our prefixes
168     */
169    @Override
170    public boolean accept(final File file) {
171        return accept(file == null ? null : file.getName());
172    }
173
174    /**
175     * Checks to see if the file name starts with the prefix.
176     *
177     * @param file  the File directory
178     * @param name  the file name
179     * @return true if the file name starts with one of our prefixes
180     */
181    @Override
182    public boolean accept(final File file, final String name) {
183        return accept(name);
184    }
185
186    /**
187     * Checks to see if the file name starts with the prefix.
188     * @param file  the File to check
189     *
190     * @return true if the file name starts with one of our prefixes
191     * @since 2.9.0
192     */
193    @Override
194    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
195        final Path fileName = file.getFileName();
196        return toFileVisitResult(accept(fileName == null ? null : fileName.toFile()), file);
197    }
198
199    private boolean accept(final String name) {
200        for (final String prefix : prefixes) {
201            if (caseSensitivity.checkStartsWith(name, prefix)) {
202                return true;
203            }
204        }
205        return false;
206    }
207
208    /**
209     * Provide a String representation of this file filter.
210     *
211     * @return a String representation
212     */
213    @Override
214    public String toString() {
215        final StringBuilder buffer = new StringBuilder();
216        buffer.append(super.toString());
217        buffer.append("(");
218        if (prefixes != null) {
219            for (int i = 0; i < prefixes.length; i++) {
220                if (i > 0) {
221                    buffer.append(",");
222                }
223                buffer.append(prefixes[i]);
224            }
225        }
226        buffer.append(")");
227        return buffer.toString();
228    }
229
230}