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