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.FileFilter;
021import java.io.FilenameFilter;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Collections;
025import java.util.Date;
026import java.util.HashSet;
027import java.util.List;
028import java.util.Objects;
029import java.util.Set;
030import java.util.stream.Collector;
031import java.util.stream.Collectors;
032import java.util.stream.Stream;
033import java.util.stream.StreamSupport;
034
035import org.apache.commons.io.FileUtils;
036import org.apache.commons.io.IOCase;
037
038/**
039 * Useful utilities for working with file filters. It provides access to all
040 * file filter implementations in this package so you don't have to import
041 * every class you use.
042 *
043 * @since 1.0
044 */
045public class FileFilterUtils {
046
047    /* Constructed on demand and then cached */
048    private static final IOFileFilter cvsFilter = notFileFilter(
049            and(directoryFileFilter(), nameFileFilter("CVS")));
050
051
052    /* Constructed on demand and then cached */
053    private static final IOFileFilter svnFilter = notFileFilter(
054            and(directoryFileFilter(), nameFileFilter(".svn")));
055
056    /**
057     * Returns a filter that returns true if the file was last modified before
058     * or at the specified cutoff date.
059     *
060     * @param cutoffDate  the time threshold
061     * @return an appropriately configured age file filter
062     * @see AgeFileFilter
063     * @since 1.2
064     */
065    public static IOFileFilter ageFileFilter(final Date cutoffDate) {
066        return new AgeFileFilter(cutoffDate);
067    }
068
069    /**
070     * Returns a filter that filters files based on a cutoff date.
071     *
072     * @param cutoffDate  the time threshold
073     * @param acceptOlder  if true, older files get accepted, if false, newer
074     * @return an appropriately configured age file filter
075     * @see AgeFileFilter
076     * @since 1.2
077     */
078    public static IOFileFilter ageFileFilter(final Date cutoffDate, final boolean acceptOlder) {
079        return new AgeFileFilter(cutoffDate, acceptOlder);
080    }
081
082    /**
083     * Returns a filter that returns true if the file was last modified before
084     * or at the same time as the specified reference file.
085     *
086     * @param cutoffReference  the file whose last modification
087     *        time is used as the threshold age of the files
088     * @return an appropriately configured age file filter
089     * @see AgeFileFilter
090     * @since 1.2
091     */
092    public static IOFileFilter ageFileFilter(final File cutoffReference) {
093        return new AgeFileFilter(cutoffReference);
094    }
095
096    /**
097     * Returns a filter that filters files based on a cutoff reference file.
098     *
099     * @param cutoffReference  the file whose last modification
100     *        time is used as the threshold age of the files
101     * @param acceptOlder  if true, older files get accepted, if false, newer
102     * @return an appropriately configured age file filter
103     * @see AgeFileFilter
104     * @since 1.2
105     */
106    public static IOFileFilter ageFileFilter(final File cutoffReference, final boolean acceptOlder) {
107        return new AgeFileFilter(cutoffReference, acceptOlder);
108    }
109
110    /**
111     * Returns a filter that returns true if the file was last modified before
112     * or at the specified cutoff time.
113     *
114     * @param cutoff  the time threshold
115     * @return an appropriately configured age file filter
116     * @see AgeFileFilter
117     * @since 1.2
118     */
119    public static IOFileFilter ageFileFilter(final long cutoff) {
120        return new AgeFileFilter(cutoff);
121    }
122
123    /**
124     * Returns a filter that filters files based on a cutoff time.
125     *
126     * @param cutoff  the time threshold
127     * @param acceptOlder  if true, older files get accepted, if false, newer
128     * @return an appropriately configured age file filter
129     * @see AgeFileFilter
130     * @since 1.2
131     */
132    public static IOFileFilter ageFileFilter(final long cutoff, final boolean acceptOlder) {
133        return new AgeFileFilter(cutoff, acceptOlder);
134    }
135
136    /**
137     * Returns a filter that ANDs the specified filters.
138     *
139     * @param filters the IOFileFilters that will be ANDed together.
140     * @return a filter that ANDs the specified filters
141     *
142     * @throws IllegalArgumentException if the filters are null or contain a
143     *         null value.
144     * @see AndFileFilter
145     * @since 2.0
146     */
147    public static IOFileFilter and(final IOFileFilter... filters) {
148        return new AndFileFilter(toList(filters));
149    }
150
151    //-----------------------------------------------------------------------
152    /**
153     * Returns a filter that ANDs the two specified filters.
154     *
155     * @param filter1  the first filter
156     * @param filter2  the second filter
157     * @return a filter that ANDs the two specified filters
158     * @see #and(IOFileFilter...)
159     * @see AndFileFilter
160     * @deprecated use {@link #and(IOFileFilter...)}
161     */
162    @Deprecated
163    public static IOFileFilter andFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
164        return new AndFileFilter(filter1, filter2);
165    }
166
167    //-----------------------------------------------------------------------
168    /**
169     * Returns an {@code IOFileFilter} that wraps the
170     * {@code FileFilter} instance.
171     *
172     * @param filter  the filter to be wrapped
173     * @return a new filter that implements IOFileFilter
174     * @see DelegateFileFilter
175     */
176    public static IOFileFilter asFileFilter(final FileFilter filter) {
177        return new DelegateFileFilter(filter);
178    }
179
180    /**
181     * Returns an {@code IOFileFilter} that wraps the
182     * {@code FilenameFilter} instance.
183     *
184     * @param filter  the filter to be wrapped
185     * @return a new filter that implements IOFileFilter
186     * @see DelegateFileFilter
187     */
188    public static IOFileFilter asFileFilter(final FilenameFilter filter) {
189        return new DelegateFileFilter(filter);
190    }
191
192    /**
193     * Returns a filter that checks if the file is a directory.
194     *
195     * @return file filter that accepts only directories and not files
196     * @see DirectoryFileFilter#DIRECTORY
197     */
198    public static IOFileFilter directoryFileFilter() {
199        return DirectoryFileFilter.DIRECTORY;
200    }
201
202    /**
203     * Returns a filter that always returns false.
204     *
205     * @return a false filter
206     * @see FalseFileFilter#FALSE
207     */
208    public static IOFileFilter falseFileFilter() {
209        return FalseFileFilter.FALSE;
210    }
211
212    /**
213     * Returns a filter that checks if the file is a file (and not a directory).
214     *
215     * @return file filter that accepts only files and not directories
216     * @see FileFileFilter#INSTANCE
217     */
218    public static IOFileFilter fileFileFilter() {
219        return FileFileFilter.INSTANCE;
220    }
221
222    /**
223     * <p>
224     * Applies an {@link IOFileFilter} to the provided {@link File}
225     * objects. The resulting array is a subset of the original file list that
226     * matches the provided filter.
227     * </p>
228     *
229     * <pre>
230     * Set&lt;File&gt; allFiles = ...
231     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
232     *     FileFilterUtils.suffixFileFilter(".java"));
233     * </pre>
234     * @param filter the filter to apply to the set of files.
235     * @param files the array of files to apply the filter to.
236     *
237     * @return a subset of {@code files} that is accepted by the
238     *         file filter.
239     * @throws IllegalArgumentException if the filter is {@code null}
240     *         or {@code files} contains a {@code null} value.
241     *
242     * @since 2.0
243     */
244    public static File[] filter(final IOFileFilter filter, final File... files) {
245        if (filter == null) {
246            throw new IllegalArgumentException("file filter is null");
247        }
248        if (files == null) {
249            return FileUtils.EMPTY_FILE_ARRAY;
250        }
251        return filterFiles(filter, Arrays.stream(files), Collectors.toList()).toArray(FileUtils.EMPTY_FILE_ARRAY);
252    }
253
254    /**
255     * <p>
256     * Applies an {@link IOFileFilter} to the provided {@link File} stream and collects the accepted files.
257     * </p>
258     *
259     * @param filter the filter to apply to the stream of files.
260     * @param stream the stream of files on which to apply the filter.
261     * @param collector how to collect the end result.
262     *
263     * @param <R> the return type.
264     * @param <A> the mutable accumulation type of the reduction operation (often hidden as an implementation detail)
265     * @return a subset of files from the stream that is accepted by the filter.
266     * @throws IllegalArgumentException if the filter is {@code null}.
267     */
268    private static <R, A> R filterFiles(final IOFileFilter filter, final Stream<File> stream,
269        final Collector<? super File, A, R> collector) {
270        //Objects.requireNonNull(filter, "filter");
271        Objects.requireNonNull(collector, "collector");
272        if (filter == null) {
273            throw new IllegalArgumentException("file filter is null");
274        }
275        if (stream == null) {
276            return Stream.<File>empty().collect(collector);
277        }
278        return stream.filter(filter::accept).collect(collector);
279    }
280
281    /**
282     * <p>
283     * Applies an {@link IOFileFilter} to the provided {@link File}
284     * objects. The resulting array is a subset of the original file list that
285     * matches the provided filter.
286     * </p>
287     *
288     * <p>
289     * The {@link Set} returned by this method is not guaranteed to be thread safe.
290     * </p>
291     *
292     * <pre>
293     * Set&lt;File&gt; allFiles = ...
294     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
295     *     FileFilterUtils.suffixFileFilter(".java"));
296     * </pre>
297     * @param filter the filter to apply to the set of files.
298     * @param files the array of files to apply the filter to.
299     *
300     * @return a subset of {@code files} that is accepted by the
301     *         file filter.
302     * @throws IllegalArgumentException if the filter is {@code null}
303     *         or {@code files} contains a {@code null} value.
304     *
305     * @since 2.0
306     */
307    public static File[] filter(final IOFileFilter filter, final Iterable<File> files) {
308        return filterList(filter, files).toArray(FileUtils.EMPTY_FILE_ARRAY);
309    }
310
311    /**
312     * <p>
313     * Applies an {@link IOFileFilter} to the provided {@link File}
314     * objects. The resulting list is a subset of the original files that
315     * matches the provided filter.
316     * </p>
317     *
318     * <p>
319     * The {@link List} returned by this method is not guaranteed to be thread safe.
320     * </p>
321     *
322     * <pre>
323     * List&lt;File&gt; filesAndDirectories = ...
324     * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
325     *     FileFilterUtils.directoryFileFilter());
326     * </pre>
327     * @param filter the filter to apply to each files in the list.
328     * @param files the collection of files to apply the filter to.
329     *
330     * @return a subset of {@code files} that is accepted by the
331     *         file filter.
332     * @throws IllegalArgumentException if the filter is {@code null}
333     *         or {@code files} contains a {@code null} value.
334     * @since 2.0
335     */
336    public static List<File> filterList(final IOFileFilter filter, final File... files) {
337        return Arrays.asList(filter(filter, files));
338    }
339
340    /**
341     * <p>
342     * Applies an {@link IOFileFilter} to the provided {@link File}
343     * objects. The resulting list is a subset of the original files that
344     * matches the provided filter.
345     * </p>
346     *
347     * <p>
348     * The {@link List} returned by this method is not guaranteed to be thread safe.
349     * </p>
350     *
351     * <pre>
352     * List&lt;File&gt; filesAndDirectories = ...
353     * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
354     *     FileFilterUtils.directoryFileFilter());
355     * </pre>
356     * @param filter the filter to apply to each files in the list.
357     * @param files the collection of files to apply the filter to.
358     *
359     * @return a subset of {@code files} that is accepted by the
360     *         file filter.
361     * @throws IllegalArgumentException if the filter is {@code null}
362     * @since 2.0
363     */
364    public static List<File> filterList(final IOFileFilter filter, final Iterable<File> files) {
365        if (files == null) {
366            return Collections.emptyList();
367        }
368        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toList());
369    }
370
371    /**
372     * <p>
373     * Applies an {@link IOFileFilter} to the provided {@link File}
374     * objects. The resulting set is a subset of the original file list that
375     * matches the provided filter.
376     * </p>
377     *
378     * <p>
379     * The {@link Set} returned by this method is not guaranteed to be thread safe.
380     * </p>
381     *
382     * <pre>
383     * Set&lt;File&gt; allFiles = ...
384     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
385     *     FileFilterUtils.suffixFileFilter(".java"));
386     * </pre>
387     * @param filter the filter to apply to the set of files.
388     * @param files the collection of files to apply the filter to.
389     *
390     * @return a subset of {@code files} that is accepted by the
391     *         file filter.
392     * @throws IllegalArgumentException if the filter is {@code null}
393     *         or {@code files} contains a {@code null} value.
394     *
395     * @since 2.0
396     */
397    public static Set<File> filterSet(final IOFileFilter filter, final File... files) {
398        return new HashSet<>(Arrays.asList(filter(filter, files)));
399    }
400
401    /**
402     * <p>
403     * Applies an {@link IOFileFilter} to the provided {@link File}
404     * objects. The resulting set is a subset of the original file list that
405     * matches the provided filter.
406     * </p>
407     *
408     * <p>
409     * The {@link Set} returned by this method is not guaranteed to be thread safe.
410     * </p>
411     *
412     * <pre>
413     * Set&lt;File&gt; allFiles = ...
414     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
415     *     FileFilterUtils.suffixFileFilter(".java"));
416     * </pre>
417     * @param filter the filter to apply to the set of files.
418     * @param files the collection of files to apply the filter to.
419     *
420     * @return a subset of {@code files} that is accepted by the
421     *         file filter.
422     * @throws IllegalArgumentException if the filter is {@code null}
423     *
424     * @since 2.0
425     */
426    public static Set<File> filterSet(final IOFileFilter filter, final Iterable<File> files) {
427        if (files == null) {
428            return Collections.emptySet();
429        }
430        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toSet());
431    }
432
433    /**
434     * Returns a filter that accepts files that begin with the provided magic
435     * number.
436     *
437     * @param magicNumber the magic number (byte sequence) to match at the
438     *        beginning of each file.
439     *
440     * @return an IOFileFilter that accepts files beginning with the provided
441     *         magic number.
442     *
443     * @throws IllegalArgumentException if {@code magicNumber} is
444     *         {@code null} or is of length zero.
445     * @see MagicNumberFileFilter
446     * @since 2.0
447     */
448    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber) {
449        return new MagicNumberFileFilter(magicNumber);
450    }
451
452    /**
453     * Returns a filter that accepts files that contains the provided magic
454     * number at a specified offset within the file.
455     *
456     * @param magicNumber the magic number (byte sequence) to match at the
457     *        provided offset in each file.
458     * @param offset the offset within the files to look for the magic number.
459     *
460     * @return an IOFileFilter that accepts files containing the magic number
461     *         at the specified offset.
462     *
463     * @throws IllegalArgumentException if {@code magicNumber} is
464     *         {@code null}, or contains no bytes, or {@code offset}
465     *         is a negative number.
466     * @see MagicNumberFileFilter
467     * @since 2.0
468     */
469    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber, final long offset) {
470        return new MagicNumberFileFilter(magicNumber, offset);
471    }
472
473    /**
474     * Returns a filter that accepts files that begin with the provided magic
475     * number.
476     *
477     * @param magicNumber the magic number (byte sequence) to match at the
478     *        beginning of each file.
479     *
480     * @return an IOFileFilter that accepts files beginning with the provided
481     *         magic number.
482     *
483     * @throws IllegalArgumentException if {@code magicNumber} is
484     *         {@code null} or the empty String.
485     * @see MagicNumberFileFilter
486     * @since 2.0
487     */
488    public static IOFileFilter magicNumberFileFilter(final String magicNumber) {
489        return new MagicNumberFileFilter(magicNumber);
490    }
491
492    /**
493     * Returns a filter that accepts files that contains the provided magic
494     * number at a specified offset within the file.
495     *
496     * @param magicNumber the magic number (byte sequence) to match at the
497     *        provided offset in each file.
498     * @param offset the offset within the files to look for the magic number.
499     *
500     * @return an IOFileFilter that accepts files containing the magic number
501     *         at the specified offset.
502     *
503     * @throws IllegalArgumentException if {@code magicNumber} is
504     *         {@code null} or the empty String, or if offset is a
505     *         negative number.
506     * @see MagicNumberFileFilter
507     * @since 2.0
508     */
509    public static IOFileFilter magicNumberFileFilter(final String magicNumber, final long offset) {
510        return new MagicNumberFileFilter(magicNumber, offset);
511    }
512
513    /**
514     * Decorates a filter to make it ignore CVS directories.
515     * Passing in {@code null} will return a filter that accepts everything
516     * except CVS directories.
517     *
518     * @param filter  the filter to decorate, null means an unrestricted filter
519     * @return the decorated filter, never null
520     * @since 1.1 (method existed but had bug in 1.0)
521     */
522    public static IOFileFilter makeCVSAware(final IOFileFilter filter) {
523        return filter == null ? cvsFilter : and(filter, cvsFilter);
524    }
525
526    //-----------------------------------------------------------------------
527    /**
528     * Decorates a filter so that it only applies to directories and not to files.
529     *
530     * @param filter  the filter to decorate, null means an unrestricted filter
531     * @return the decorated filter, never null
532     * @see DirectoryFileFilter#DIRECTORY
533     * @since 1.3
534     */
535    public static IOFileFilter makeDirectoryOnly(final IOFileFilter filter) {
536        if (filter == null) {
537            return DirectoryFileFilter.DIRECTORY;
538        }
539        return DirectoryFileFilter.DIRECTORY.and(filter);
540    }
541
542    /**
543     * Decorates a filter so that it only applies to files and not to directories.
544     *
545     * @param filter  the filter to decorate, null means an unrestricted filter
546     * @return the decorated filter, never null
547     * @see FileFileFilter#INSTANCE
548     * @since 1.3
549     */
550    public static IOFileFilter makeFileOnly(final IOFileFilter filter) {
551        if (filter == null) {
552            return FileFileFilter.INSTANCE;
553        }
554        return FileFileFilter.INSTANCE.and(filter);
555    }
556
557    /**
558     * Decorates a filter to make it ignore SVN directories.
559     * Passing in {@code null} will return a filter that accepts everything
560     * except SVN directories.
561     *
562     * @param filter  the filter to decorate, null means an unrestricted filter
563     * @return the decorated filter, never null
564     * @since 1.1
565     */
566    public static IOFileFilter makeSVNAware(final IOFileFilter filter) {
567        return filter == null ? svnFilter : and(filter, svnFilter);
568    }
569
570    /**
571     * Returns a filter that returns true if the file name matches the specified text.
572     *
573     * @param name  the file name
574     * @return a name checking filter
575     * @see NameFileFilter
576     */
577    public static IOFileFilter nameFileFilter(final String name) {
578        return new NameFileFilter(name);
579    }
580
581    /**
582     * Returns a filter that returns true if the file name matches the specified text.
583     *
584     * @param name  the file name
585     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
586     * @return a name checking filter
587     * @see NameFileFilter
588     * @since 2.0
589     */
590    public static IOFileFilter nameFileFilter(final String name, final IOCase caseSensitivity) {
591        return new NameFileFilter(name, caseSensitivity);
592    }
593
594    /**
595     * Returns a filter that NOTs the specified filter.
596     *
597     * @param filter  the filter to invert
598     * @return a filter that NOTs the specified filter
599     * @see NotFileFilter
600     */
601    public static IOFileFilter notFileFilter(final IOFileFilter filter) {
602        return filter.negate();
603    }
604
605    /**
606     * Returns a filter that ORs the specified filters.
607     *
608     * @param filters the IOFileFilters that will be ORed together.
609     * @return a filter that ORs the specified filters
610     *
611     * @throws IllegalArgumentException if the filters are null or contain a
612     *         null value.
613     * @see OrFileFilter
614     * @since 2.0
615     */
616    public static IOFileFilter or(final IOFileFilter... filters) {
617        return new OrFileFilter(toList(filters));
618    }
619
620    /**
621     * Returns a filter that ORs the two specified filters.
622     *
623     * @param filter1  the first filter
624     * @param filter2  the second filter
625     * @return a filter that ORs the two specified filters
626     * @see #or(IOFileFilter...)
627     * @see OrFileFilter
628     * @deprecated use {@link #or(IOFileFilter...)}
629     */
630    @Deprecated
631    public static IOFileFilter orFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
632        return new OrFileFilter(filter1, filter2);
633    }
634
635    /**
636     * Returns a filter that returns true if the file name starts with the specified text.
637     *
638     * @param prefix  the file name prefix
639     * @return a prefix checking filter
640     * @see PrefixFileFilter
641     */
642    public static IOFileFilter prefixFileFilter(final String prefix) {
643        return new PrefixFileFilter(prefix);
644    }
645
646    /**
647     * Returns a filter that returns true if the file name starts with the specified text.
648     *
649     * @param prefix  the file name prefix
650     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
651     * @return a prefix checking filter
652     * @see PrefixFileFilter
653     * @since 2.0
654     */
655    public static IOFileFilter prefixFileFilter(final String prefix, final IOCase caseSensitivity) {
656        return new PrefixFileFilter(prefix, caseSensitivity);
657    }
658
659    //-----------------------------------------------------------------------
660    /**
661     * Returns a filter that returns true if the file is bigger than a certain size.
662     *
663     * @param threshold  the file size threshold
664     * @return an appropriately configured SizeFileFilter
665     * @see SizeFileFilter
666     * @since 1.2
667     */
668    public static IOFileFilter sizeFileFilter(final long threshold) {
669        return new SizeFileFilter(threshold);
670    }
671
672    /**
673     * Returns a filter that filters based on file size.
674     *
675     * @param threshold  the file size threshold
676     * @param acceptLarger  if true, larger files get accepted, if false, smaller
677     * @return an appropriately configured SizeFileFilter
678     * @see SizeFileFilter
679     * @since 1.2
680     */
681    public static IOFileFilter sizeFileFilter(final long threshold, final boolean acceptLarger) {
682        return new SizeFileFilter(threshold, acceptLarger);
683    }
684
685    /**
686     * Returns a filter that accepts files whose size is &gt;= minimum size
687     * and &lt;= maximum size.
688     *
689     * @param minSizeInclusive the minimum file size (inclusive)
690     * @param maxSizeInclusive the maximum file size (inclusive)
691     * @return an appropriately configured IOFileFilter
692     * @see SizeFileFilter
693     * @since 1.3
694     */
695    public static IOFileFilter sizeRangeFileFilter(final long minSizeInclusive, final long maxSizeInclusive ) {
696        final IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
697        final IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
698        return minimumFilter.and(maximumFilter);
699    }
700
701    /**
702     * Returns a filter that returns true if the file name ends with the specified text.
703     *
704     * @param suffix  the file name suffix
705     * @return a suffix checking filter
706     * @see SuffixFileFilter
707     */
708    public static IOFileFilter suffixFileFilter(final String suffix) {
709        return new SuffixFileFilter(suffix);
710    }
711
712    /**
713     * Returns a filter that returns true if the file name ends with the specified text.
714     *
715     * @param suffix  the file name suffix
716     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
717     * @return a suffix checking filter
718     * @see SuffixFileFilter
719     * @since 2.0
720     */
721    public static IOFileFilter suffixFileFilter(final String suffix, final IOCase caseSensitivity) {
722        return new SuffixFileFilter(suffix, caseSensitivity);
723    }
724
725    /**
726     * Create a List of file filters.
727     *
728     * @param filters The file filters
729     * @return The list of file filters
730     * @throws IllegalArgumentException if the filters are null or contain a
731     *         null value.
732     * @since 2.0
733     */
734    public static List<IOFileFilter> toList(final IOFileFilter... filters) {
735        if (filters == null) {
736            throw new IllegalArgumentException("The filters must not be null");
737        }
738        final List<IOFileFilter> list = new ArrayList<>(filters.length);
739        for (int i = 0; i < filters.length; i++) {
740            if (filters[i] == null) {
741                throw new IllegalArgumentException("The filter[" + i + "] is null");
742            }
743            list.add(filters[i]);
744        }
745        return list;
746    }
747
748    /**
749     * Returns a filter that always returns true.
750     *
751     * @return a true filter
752     * @see TrueFileFilter#TRUE
753     */
754    public static IOFileFilter trueFileFilter() {
755        return TrueFileFilter.TRUE;
756    }
757
758    /**
759     * FileFilterUtils is not normally instantiated.
760     */
761    public FileFilterUtils() {
762    }
763
764}