    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     * @param filter the filter to apply to the set of files.
    230     * @param files the array of files to apply the filter to.
    231     * @return a subset of {@code files} that is accepted by the
    232     *         file filter.
    233     * @throws NullPointerException if the filter is {@code null}
    234     *         or {@code files} contains a {@code null} value.
    235     *
    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     * @param filter the filter to apply to the set of files.
    263     * @param files the array of files to apply the filter to.
    264     * @return a subset of {@code files} that is accepted by the
    265     *         file filter.
    266     * @throws IllegalArgumentException if the filter is {@code null}
    267     *         or {@code files} contains a {@code null} value.
    268     *
    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     * @param filter the filter to apply to each files in the list.
    315     * @param files the collection of files to apply the filter to.
    316     * @return a subset of {@code files} that is accepted by the
    317     *         file filter.
    318     * @throws IllegalArgumentException if the filter is {@code null}
    319     *         or {@code files} contains a {@code null} value.
    320     * @since 2.0
    321     */
    322    public static List<File> filterList(final IOFileFilter filter, final File... files) {
    323        return Arrays.asList(filter(filter, files));
    324    }
    325
    326    /**
    327     * <p>
    328     * Applies an {@link IOFileFilter} to the provided {@link File}
    329     * objects. The resulting list is a subset of the original files that
    330     * matches the provided filter.
    331     * </p>
    332     *
    333     * <p>
    334     * The {@link List} returned by this method is not guaranteed to be thread safe.
    335     * </p>
    336     *
    337     * <pre>
    338     * List&lt;File&gt; filesAndDirectories = ...
    339     * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
    340     *     FileFilterUtils.directoryFileFilter());
    341     * </pre>
    342     * @param filter the filter to apply to each files in the list.
    343     * @param files the collection of files to apply the filter to.
    344     * @return a subset of {@code files} that is accepted by the
    345     *         file filter.
    346     * @throws IllegalArgumentException if the filter is {@code null}
    347     * @since 2.0
    348     */
    349    public static List<File> filterList(final IOFileFilter filter, final Iterable<File> files) {
    350        if (files == null) {
    351            return Collections.emptyList();
    352        }
    353        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toList());
    354    }
    355
    356    /**
    357     * <p>
    358     * Applies an {@link IOFileFilter} to the provided {@link File}
    359     * objects. The resulting set is a subset of the original file list that
    360     * matches the provided filter.
    361     * </p>
    362     *
    363     * <p>
    364     * The {@link Set} returned by this method is not guaranteed to be thread safe.
    365     * </p>
    366     *
    367     * <pre>
    368     * Set&lt;File&gt; allFiles = ...
    369     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
    370     *     FileFilterUtils.suffixFileFilter(".java"));
    371     * </pre>
    372     * @param filter the filter to apply to the set of files.
    373     * @param files the collection of files to apply the filter to.
    374     * @return a subset of {@code files} that is accepted by the
    375     *         file filter.
    376     * @throws IllegalArgumentException if the filter is {@code null}
    377     *         or {@code files} contains a {@code null} value.
    378     *
    379     * @since 2.0
    380     */
    381    public static Set<File> filterSet(final IOFileFilter filter, final File... files) {
    382        return new HashSet<>(Arrays.asList(filter(filter, files)));
    383    }
    384
    385    /**
    386     * <p>
    387     * Applies an {@link IOFileFilter} to the provided {@link File}
    388     * objects. The resulting set is a subset of the original file list that
    389     * matches the provided filter.
    390     * </p>
    391     *
    392     * <p>
    393     * The {@link Set} returned by this method is not guaranteed to be thread safe.
    394     * </p>
    395     *
    396     * <pre>
    397     * Set&lt;File&gt; allFiles = ...
    398     * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
    399     *     FileFilterUtils.suffixFileFilter(".java"));
    400     * </pre>
    401     * @param filter the filter to apply to the set of files.
    402     * @param files the collection of files to apply the filter to.
    403     * @return a subset of {@code files} that is accepted by the
    404     *         file filter.
    405     * @throws IllegalArgumentException if the filter is {@code null}
    406     * @since 2.0
    407     */
    408    public static Set<File> filterSet(final IOFileFilter filter, final Iterable<File> files) {
    409        if (files == null) {
    410            return Collections.emptySet();
    411        }
    412        return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toSet());
    413    }
    414
    415    /**
    416     * Returns a filter that accepts files that begin with the provided magic
    417     * number.
    418     *
    419     * @param magicNumber the magic number (byte sequence) to match at the
    420     *        beginning of each file.
    421     *
    422     * @return an IOFileFilter that accepts files beginning with the provided
    423     *         magic number.
    424     *
    425     * @throws IllegalArgumentException if {@code magicNumber} is
    426     *         {@code null} or is of length zero.
    427     * @see MagicNumberFileFilter
    428     * @since 2.0
    429     */
    430    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber) {
    431        return new MagicNumberFileFilter(magicNumber);
    432    }
    433
    434    /**
    435     * Returns a filter that accepts files that contains the provided magic
    436     * number at a specified offset within the file.
    437     *
    438     * @param magicNumber the magic number (byte sequence) to match at the
    439     *        provided offset in each file.
    440     * @param offset the offset within the files to look for the magic number.
    441     * @return an IOFileFilter that accepts files containing the magic number
    442     *         at the specified offset.
    443     *
    444     * @throws IllegalArgumentException if {@code magicNumber} is
    445     *         {@code null}, or contains no bytes, or {@code offset}
    446     *         is a negative number.
    447     * @see MagicNumberFileFilter
    448     * @since 2.0
    449     */
    450    public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber, final long offset) {
    451        return new MagicNumberFileFilter(magicNumber, offset);
    452    }
    453
    454    /**
    455     * Returns a filter that accepts files that begin with the provided magic
    456     * number.
    457     *
    458     * @param magicNumber the magic number (byte sequence) to match at the
    459     *        beginning of each file.
    460     *
    461     * @return an IOFileFilter that accepts files beginning with the provided
    462     *         magic number.
    463     *
    464     * @throws IllegalArgumentException if {@code magicNumber} is
    465     *         {@code null} or the empty String.
    466     * @see MagicNumberFileFilter
    467     * @since 2.0
    468     */
    469    public static IOFileFilter magicNumberFileFilter(final String magicNumber) {
    470        return new MagicNumberFileFilter(magicNumber);
    471    }
    472
    473    /**
    474     * Returns a filter that accepts files that contains the provided magic
    475     * number at a specified offset within the file.
    476     *
    477     * @param magicNumber the magic number (byte sequence) to match at the
    478     *        provided offset in each file.
    479     * @param offset the offset within the files to look for the magic number.
    480     * @return an IOFileFilter that accepts files containing the magic number
    481     *         at the specified offset.
    482     *
    483     * @throws IllegalArgumentException if {@code magicNumber} is
    484     *         {@code null} or the empty String, or if offset is a
    485     *         negative number.
    486     * @see MagicNumberFileFilter
    487     * @since 2.0
    488     */
    489    public static IOFileFilter magicNumberFileFilter(final String magicNumber, final long offset) {
    490        return new MagicNumberFileFilter(magicNumber, offset);
    491    }
    492
    493    /**
    494     * Decorates a filter to make it ignore CVS directories.
    495     * Passing in {@code null} will return a filter that accepts everything
    496     * except CVS directories.
    497     *
    498     * @param filter  the filter to decorate, null means an unrestricted filter
    499     * @return the decorated filter, never null
    500     * @since 1.1 (method existed but had a bug in 1.0)
    501     */
    502    public static IOFileFilter makeCVSAware(final IOFileFilter filter) {
    503        return filter == null ? CVS_FILTER : and(filter, CVS_FILTER);
    504    }
    505
    506    /**
    507     * Decorates a filter so that it only applies to directories and not to files.
    508     *
    509     * @param filter  the filter to decorate, null means an unrestricted filter
    510     * @return the decorated filter, never null
    511     * @see DirectoryFileFilter#DIRECTORY
    512     * @since 1.3
    513     */
    514    public static IOFileFilter makeDirectoryOnly(final IOFileFilter filter) {
    515        if (filter == null) {
    516            return DirectoryFileFilter.DIRECTORY;
    517        }
    518        return DirectoryFileFilter.DIRECTORY.and(filter);
    519    }
    520
    521    /**
    522     * Decorates a filter so that it only applies to files and not to directories.
    523     *
    524     * @param filter  the filter to decorate, null means an unrestricted filter
    525     * @return the decorated filter, never null
    526     * @see FileFileFilter#INSTANCE
    527     * @since 1.3
    528     */
    529    public static IOFileFilter makeFileOnly(final IOFileFilter filter) {
    530        if (filter == null) {
    531            return FileFileFilter.INSTANCE;
    532        }
    533        return FileFileFilter.INSTANCE.and(filter);
    534    }
    535
    536    /**
    537     * Decorates a filter to make it ignore SVN directories.
    538     * Passing in {@code null} will return a filter that accepts everything
    539     * except SVN directories.
    540     *
    541     * @param filter  the filter to decorate, null means an unrestricted filter
    542     * @return the decorated filter, never null
    543     * @since 1.1
    544     */
    545    public static IOFileFilter makeSVNAware(final IOFileFilter filter) {
    546        return filter == null ? SVN_FILTER : and(filter, SVN_FILTER);
    547    }
    548
    549    /**
    550     * Returns a filter that returns true if the file name matches the specified text.
    551     *
    552     * @param name  the file name
    553     * @return a name checking filter
    554     * @see NameFileFilter
    555     */
    556    public static IOFileFilter nameFileFilter(final String name) {
    557        return new NameFileFilter(name);
    558    }
    559
    560    /**
    561     * Returns a filter that returns true if the file name matches the specified text.
    562     *
    563     * @param name  the file name
    564     * @param ioCase  how to handle case sensitivity, null means case-sensitive
    565     * @return a name checking filter
    566     * @see NameFileFilter
    567     * @since 2.0
    568     */
    569    public static IOFileFilter nameFileFilter(final String name, final IOCase ioCase) {
    570        return new NameFileFilter(name, ioCase);
    571    }
    572
    573    /**
    574     * Returns a filter that NOTs the specified filter.
    575     *
    576     * @param filter  the filter to invert
    577     * @return a filter that NOTs the specified filter
    578     * @see NotFileFilter
    579     */
    580    public static IOFileFilter notFileFilter(final IOFileFilter filter) {
    581        return filter.negate();
    582    }
    583
    584    /**
    585     * Returns a filter that ORs the specified filters.
    586     *
    587     * @param filters the IOFileFilters that will be ORed together.
    588     * @return a filter that ORs the specified filters
    589     * @throws IllegalArgumentException if the filters are null or contain a
    590     *         null value.
    591     * @see OrFileFilter
    592     * @since 2.0
    593     */
    594    public static IOFileFilter or(final IOFileFilter... filters) {
    595        return new OrFileFilter(toList(filters));
    596    }
    597
    598    /**
    599     * Returns a filter that ORs the two specified filters.
    600     *
    601     * @param filter1  the first filter
    602     * @param filter2  the second filter
    603     * @return a filter that ORs the two specified filters
    604     * @see #or(IOFileFilter...)
    605     * @see OrFileFilter
    606     * @deprecated use {@link #or(IOFileFilter...)}
    607     */
    608    @Deprecated
    609    public static IOFileFilter orFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
    610        return new OrFileFilter(filter1, filter2);
    611    }
    612
    613    /**
    614     * Returns a filter that returns true if the file name starts with the specified text.
    615     *
    616     * @param prefix  the file name prefix
    617     * @return a prefix checking filter
    618     * @see PrefixFileFilter
    619     */
    620    public static IOFileFilter prefixFileFilter(final String prefix) {
    621        return new PrefixFileFilter(prefix);
    622    }
    623
    624    /**
    625     * Returns a filter that returns true if the file name starts with the specified text.
    626     *
    627     * @param prefix  the file name prefix
    628     * @param ioCase  how to handle case sensitivity, null means case-sensitive
    629     * @return a prefix checking filter
    630     * @see PrefixFileFilter
    631     * @since 2.0
    632     */
    633    public static IOFileFilter prefixFileFilter(final String prefix, final IOCase ioCase) {
    634        return new PrefixFileFilter(prefix, ioCase);
    635    }
    636
    637    /**
    638     * Returns a filter that returns true if the file is bigger than a certain size.
    639     *
    640     * @param threshold  the file size threshold
    641     * @return an appropriately configured SizeFileFilter
    642     * @see SizeFileFilter
    643     * @since 1.2
    644     */
    645    public static IOFileFilter sizeFileFilter(final long threshold) {
    646        return new SizeFileFilter(threshold);
    647    }
    648
    649    /**
    650     * Returns a filter that filters based on file size.
    651     *
    652     * @param threshold  the file size threshold
    653     * @param acceptLarger  if true, larger files get accepted, if false, smaller
    654     * @return an appropriately configured SizeFileFilter
    655     * @see SizeFileFilter
    656     * @since 1.2
    657     */
    658    public static IOFileFilter sizeFileFilter(final long threshold, final boolean acceptLarger) {
    659        return new SizeFileFilter(threshold, acceptLarger);
    660    }
    661
    662    /**
    663     * Returns a filter that accepts files whose size is &gt;= minimum size
    664     * and &lt;= maximum size.
    665     *
    666     * @param minSizeInclusive the minimum file size (inclusive)
    667     * @param maxSizeInclusive the maximum file size (inclusive)
    668     * @return an appropriately configured IOFileFilter
    669     * @see SizeFileFilter
    670     * @since 1.3
    671     */
    672    public static IOFileFilter sizeRangeFileFilter(final long minSizeInclusive, final long maxSizeInclusive) {
    673        final IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
    674        final IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
    675        return minimumFilter.and(maximumFilter);
    676    }
    677
    678    /**
    679     * Returns a filter that returns true if the file name ends with the specified text.
    680     *
    681     * @param suffix  the file name suffix
    682     * @return a suffix checking filter
    683     * @see SuffixFileFilter
    684     */
    685    public static IOFileFilter suffixFileFilter(final String suffix) {
    686        return new SuffixFileFilter(suffix);
    687    }
    688
    689    /**
    690     * Returns a filter that returns true if the file name ends with the specified text.
    691     *
    692     * @param suffix  the file name suffix
    693     * @param ioCase  how to handle case sensitivity, null means case-sensitive
    694     * @return a suffix checking filter
    695     * @see SuffixFileFilter
    696     * @since 2.0
    697     */
    698    public static IOFileFilter suffixFileFilter(final String suffix, final IOCase ioCase) {
    699        return new SuffixFileFilter(suffix, ioCase);
    700    }
    701
    702    /**
    703     * Create a List of file filters.
    704     *
    705     * @param filters The file filters
    706     * @return The list of file filters
    707     * @throws NullPointerException if the filters are null or contain a
    708     *         null value.
    709     * @since 2.0
    710     */
    711    public static List<IOFileFilter> toList(final IOFileFilter... filters) {
    712        return Stream.of(Objects.requireNonNull(filters, "filters")).map(Objects::requireNonNull).collect(Collectors.toList());
    713    }
    714
    715    /**
    716     * Returns a filter that always returns true.
    717     *
    718     * @return a true filter
    719     * @see TrueFileFilter#TRUE
    720     */
    721    public static IOFileFilter trueFileFilter() {
    722        return TrueFileFilter.TRUE;
    723    }
    724
    725    /**
    726     * FileFilterUtils is not normally instantiated.
    727     */
    728    public FileFilterUtils() {
    729    }
    730
    731}