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