View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io.filefilter;
18  
19  import java.io.File;
20  import java.io.FileFilter;
21  import java.io.FilenameFilter;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.commons.io.IOCase;
31  
32  /**
33   * Useful utilities for working with file filters. It provides access to all
34   * file filter implementations in this package so you don't have to import
35   * every class you use.
36   *
37   * @since 1.0
38   * @version $Id: FileFilterUtils.java 1471767 2013-04-24 23:24:19Z sebb $
39   */
40  public class FileFilterUtils {
41  
42      /**
43       * FileFilterUtils is not normally instantiated.
44       */
45      public FileFilterUtils() {
46      }
47  
48      //-----------------------------------------------------------------------
49  
50      /**
51       * <p>
52       * Applies an {@link IOFileFilter} to the provided {@link File}
53       * objects. The resulting array is a subset of the original file list that
54       * matches the provided filter.
55       * </p>
56       *
57       * <p>
58       * The {@link Set} returned by this method is not guaranteed to be thread safe.
59       * </p>
60       *
61       * <pre>
62       * Set&lt;File&gt; allFiles = ...
63       * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
64       *     FileFilterUtils.suffixFileFilter(".java"));
65       * </pre>
66       * @param filter the filter to apply to the set of files.
67       * @param files the array of files to apply the filter to.
68       *
69       * @return a subset of <code>files</code> that is accepted by the
70       *         file filter.
71       * @throws IllegalArgumentException if the filter is {@code null}
72       *         or <code>files</code> contains a {@code null} value.
73       *
74       * @since 2.0
75       */
76      public static File[] filter(final IOFileFilter filter, final File... files) {
77          if (filter == null) {
78              throw new IllegalArgumentException("file filter is null");
79          }
80          if (files == null) {
81              return new File[0];
82          }
83          final List<File> acceptedFiles = new ArrayList<File>();
84          for (final File file : files) {
85              if (file == null) {
86                  throw new IllegalArgumentException("file array contains null");
87              }
88              if (filter.accept(file)) {
89                  acceptedFiles.add(file);
90              }
91          }
92          return acceptedFiles.toArray(new File[acceptedFiles.size()]);
93      }
94  
95      /**
96       * <p>
97       * Applies an {@link IOFileFilter} to the provided {@link File}
98       * objects. The resulting array is a subset of the original file list that
99       * matches the provided filter.
100      * </p>
101      *
102      * <p>
103      * The {@link Set} returned by this method is not guaranteed to be thread safe.
104      * </p>
105      *
106      * <pre>
107      * Set&lt;File&gt; allFiles = ...
108      * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
109      *     FileFilterUtils.suffixFileFilter(".java"));
110      * </pre>
111      * @param filter the filter to apply to the set of files.
112      * @param files the array of files to apply the filter to.
113      *
114      * @return a subset of <code>files</code> that is accepted by the
115      *         file filter.
116      * @throws IllegalArgumentException if the filter is {@code null}
117      *         or <code>files</code> contains a {@code null} value.
118      *
119      * @since 2.0
120      */
121     public static File[] filter(final IOFileFilter filter, final Iterable<File> files) {
122         final List<File> acceptedFiles = filterList(filter, files);
123         return acceptedFiles.toArray(new File[acceptedFiles.size()]);
124     }
125 
126     /**
127      * <p>
128      * Applies an {@link IOFileFilter} to the provided {@link File}
129      * objects. The resulting list is a subset of the original files that
130      * matches the provided filter.
131      * </p>
132      *
133      * <p>
134      * The {@link List} returned by this method is not guaranteed to be thread safe.
135      * </p>
136      *
137      * <pre>
138      * List&lt;File&gt; filesAndDirectories = ...
139      * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
140      *     FileFilterUtils.directoryFileFilter());
141      * </pre>
142      * @param filter the filter to apply to each files in the list.
143      * @param files the collection of files to apply the filter to.
144      *
145      * @return a subset of <code>files</code> that is accepted by the
146      *         file filter.
147      * @throws IllegalArgumentException if the filter is {@code null}
148      *         or <code>files</code> contains a {@code null} value.
149      * @since 2.0
150      */
151     public static List<File> filterList(final IOFileFilter filter, final Iterable<File> files) {
152         return filter(filter, files, new ArrayList<File>());
153     }
154 
155     /**
156      * <p>
157      * Applies an {@link IOFileFilter} to the provided {@link File}
158      * objects. The resulting list is a subset of the original files that
159      * matches the provided filter.
160      * </p>
161      *
162      * <p>
163      * The {@link List} returned by this method is not guaranteed to be thread safe.
164      * </p>
165      *
166      * <pre>
167      * List&lt;File&gt; filesAndDirectories = ...
168      * List&lt;File&gt; directories = FileFilterUtils.filterList(filesAndDirectories,
169      *     FileFilterUtils.directoryFileFilter());
170      * </pre>
171      * @param filter the filter to apply to each files in the list.
172      * @param files the collection of files to apply the filter to.
173      *
174      * @return a subset of <code>files</code> that is accepted by the
175      *         file filter.
176      * @throws IllegalArgumentException if the filter is {@code null}
177      *         or <code>files</code> contains a {@code null} value.
178      * @since 2.0
179      */
180     public static List<File> filterList(final IOFileFilter filter, final File... files) {
181         final File[] acceptedFiles = filter(filter, files);
182         return Arrays.asList(acceptedFiles);
183     }
184 
185     /**
186      * <p>
187      * Applies an {@link IOFileFilter} to the provided {@link File}
188      * objects. The resulting set is a subset of the original file list that
189      * matches the provided filter.
190      * </p>
191      *
192      * <p>
193      * The {@link Set} returned by this method is not guaranteed to be thread safe.
194      * </p>
195      *
196      * <pre>
197      * Set&lt;File&gt; allFiles = ...
198      * Set&lt;File&gt; javaFiles = FileFilterUtils.filterSet(allFiles,
199      *     FileFilterUtils.suffixFileFilter(".java"));
200      * </pre>
201      * @param filter the filter to apply to the set of files.
202      * @param files the collection of files to apply the filter to.
203      *
204      * @return a subset of <code>files</code> that is accepted by the
205      *         file filter.
206      * @throws IllegalArgumentException if the filter is {@code null}
207      *         or <code>files</code> contains a {@code null} value.
208      *
209      * @since 2.0
210      */
211     public static Set<File> filterSet(final IOFileFilter filter, final File... files) {
212         final File[] acceptedFiles = filter(filter, files);
213         return new HashSet<File>(Arrays.asList(acceptedFiles));
214     }
215 
216     /**
217      * <p>
218      * Applies an {@link IOFileFilter} to the provided {@link File}
219      * objects. The resulting set is a subset of the original file list that
220      * matches the provided filter.
221      * </p>
222      *
223      * <p>
224      * The {@link Set} returned by this method is not guaranteed to be thread safe.
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 collection of files to apply the filter to.
234      *
235      * @return a subset of <code>files</code> that is accepted by the
236      *         file filter.
237      * @throws IllegalArgumentException if the filter is {@code null}
238      *         or <code>files</code> contains a {@code null} value.
239      *
240      * @since 2.0
241      */
242     public static Set<File> filterSet(final IOFileFilter filter, final Iterable<File> files) {
243         return filter(filter, files, new HashSet<File>());
244     }
245 
246     /**
247      * <p>
248      * Applies an {@link IOFileFilter} to the provided {@link File}
249      * objects and appends the accepted files to the other supplied collection.
250      * </p>
251      *
252      * <pre>
253      * List&lt;File&gt; files = ...
254      * List&lt;File&gt; directories = FileFilterUtils.filterList(files,
255      *     FileFilterUtils.sizeFileFilter(FileUtils.FIFTY_MB),
256      *         new ArrayList&lt;File&gt;());
257      * </pre>
258      * @param filter the filter to apply to the collection of files.
259      * @param files the collection of files to apply the filter to.
260      * @param acceptedFiles the list of files to add accepted files to.
261      *
262      * @param <T> the type of the file collection.
263      * @return a subset of <code>files</code> that is accepted by the
264      *         file filter.
265      * @throws IllegalArgumentException if the filter is {@code null}
266      *         or <code>files</code> contains a {@code null} value.
267      */
268     private static <T extends Collection<File>> T filter(final IOFileFilter filter,
269             final Iterable<File> files, final T acceptedFiles) {
270         if (filter == null) {
271             throw new IllegalArgumentException("file filter is null");
272         }
273         if (files != null) {
274             for (final File file : files) {
275                 if (file == null) {
276                     throw new IllegalArgumentException("file collection contains null");
277                 }
278                 if (filter.accept(file)) {
279                     acceptedFiles.add(file);
280                 }
281             }
282         }
283         return acceptedFiles;
284     }
285 
286     /**
287      * Returns a filter that returns true if the filename starts with the specified text.
288      *
289      * @param prefix  the filename prefix
290      * @return a prefix checking filter
291      * @see PrefixFileFilter
292      */
293     public static IOFileFilter prefixFileFilter(final String prefix) {
294         return new PrefixFileFilter(prefix);
295     }
296 
297     /**
298      * Returns a filter that returns true if the filename starts with the specified text.
299      *
300      * @param prefix  the filename prefix
301      * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
302      * @return a prefix checking filter
303      * @see PrefixFileFilter
304      * @since 2.0
305      */
306     public static IOFileFilter prefixFileFilter(final String prefix, final IOCase caseSensitivity) {
307         return new PrefixFileFilter(prefix, caseSensitivity);
308     }
309 
310     /**
311      * Returns a filter that returns true if the filename ends with the specified text.
312      *
313      * @param suffix  the filename suffix
314      * @return a suffix checking filter
315      * @see SuffixFileFilter
316      */
317     public static IOFileFilter suffixFileFilter(final String suffix) {
318         return new SuffixFileFilter(suffix);
319     }
320 
321     /**
322      * Returns a filter that returns true if the filename ends with the specified text.
323      *
324      * @param suffix  the filename suffix
325      * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
326      * @return a suffix checking filter
327      * @see SuffixFileFilter
328      * @since 2.0
329      */
330     public static IOFileFilter suffixFileFilter(final String suffix, final IOCase caseSensitivity) {
331         return new SuffixFileFilter(suffix, caseSensitivity);
332     }
333 
334     /**
335      * Returns a filter that returns true if the filename matches the specified text.
336      *
337      * @param name  the filename
338      * @return a name checking filter
339      * @see NameFileFilter
340      */
341     public static IOFileFilter nameFileFilter(final String name) {
342         return new NameFileFilter(name);
343     }
344 
345     /**
346      * Returns a filter that returns true if the filename matches the specified text.
347      *
348      * @param name  the filename
349      * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
350      * @return a name checking filter
351      * @see NameFileFilter
352      * @since 2.0
353      */
354     public static IOFileFilter nameFileFilter(final String name, final IOCase caseSensitivity) {
355         return new NameFileFilter(name, caseSensitivity);
356     }
357 
358     /**
359      * Returns a filter that checks if the file is a directory.
360      *
361      * @return file filter that accepts only directories and not files
362      * @see DirectoryFileFilter#DIRECTORY
363      */
364     public static IOFileFilter directoryFileFilter() {
365         return DirectoryFileFilter.DIRECTORY;
366     }
367 
368     /**
369      * Returns a filter that checks if the file is a file (and not a directory).
370      *
371      * @return file filter that accepts only files and not directories
372      * @see FileFileFilter#FILE
373      */
374     public static IOFileFilter fileFileFilter() {
375         return FileFileFilter.FILE;
376     }
377 
378     //-----------------------------------------------------------------------
379     /**
380      * Returns a filter that ANDs the two specified filters.
381      *
382      * @param filter1  the first filter
383      * @param filter2  the second filter
384      * @return a filter that ANDs the two specified filters
385      * @see #and(IOFileFilter...)
386      * @see AndFileFilter
387      * @deprecated use {@link #and(IOFileFilter...)}
388      */
389     @Deprecated
390     public static IOFileFilter andFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
391         return new AndFileFilter(filter1, filter2);
392     }
393 
394     /**
395      * Returns a filter that ORs the two specified filters.
396      *
397      * @param filter1  the first filter
398      * @param filter2  the second filter
399      * @return a filter that ORs the two specified filters
400      * @see #or(IOFileFilter...)
401      * @see OrFileFilter
402      * @deprecated use {@link #or(IOFileFilter...)}
403      */
404     @Deprecated
405     public static IOFileFilter orFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
406         return new OrFileFilter(filter1, filter2);
407     }
408 
409     /**
410      * Returns a filter that ANDs the specified filters.
411      *
412      * @param filters the IOFileFilters that will be ANDed together.
413      * @return a filter that ANDs the specified filters
414      *
415      * @throws IllegalArgumentException if the filters are null or contain a
416      *         null value.
417      * @see AndFileFilter
418      * @since 2.0
419      */
420     public static IOFileFilter and(final IOFileFilter... filters) {
421         return new AndFileFilter(toList(filters));
422     }
423 
424     /**
425      * Returns a filter that ORs the specified filters.
426      *
427      * @param filters the IOFileFilters that will be ORed together.
428      * @return a filter that ORs the specified filters
429      *
430      * @throws IllegalArgumentException if the filters are null or contain a
431      *         null value.
432      * @see OrFileFilter
433      * @since 2.0
434      */
435     public static IOFileFilter or(final IOFileFilter... filters) {
436         return new OrFileFilter(toList(filters));
437     }
438 
439     /**
440      * Create a List of file filters.
441      *
442      * @param filters The file filters
443      * @return The list of file filters
444      * @throws IllegalArgumentException if the filters are null or contain a
445      *         null value.
446      * @since 2.0
447      */
448     public static List<IOFileFilter> toList(final IOFileFilter... filters) {
449         if (filters == null) {
450             throw new IllegalArgumentException("The filters must not be null");
451         }
452         final List<IOFileFilter> list = new ArrayList<IOFileFilter>(filters.length);
453         for (int i = 0; i < filters.length; i++) {
454             if (filters[i] == null) {
455                 throw new IllegalArgumentException("The filter[" + i + "] is null");
456             }
457             list.add(filters[i]);
458         }
459         return list;
460     }
461 
462     /**
463      * Returns a filter that NOTs the specified filter.
464      *
465      * @param filter  the filter to invert
466      * @return a filter that NOTs the specified filter
467      * @see NotFileFilter
468      */
469     public static IOFileFilter notFileFilter(final IOFileFilter filter) {
470         return new NotFileFilter(filter);
471     }
472 
473     //-----------------------------------------------------------------------
474     /**
475      * Returns a filter that always returns true.
476      *
477      * @return a true filter
478      * @see TrueFileFilter#TRUE
479      */
480     public static IOFileFilter trueFileFilter() {
481         return TrueFileFilter.TRUE;
482     }
483 
484     /**
485      * Returns a filter that always returns false.
486      *
487      * @return a false filter
488      * @see FalseFileFilter#FALSE
489      */
490     public static IOFileFilter falseFileFilter() {
491         return FalseFileFilter.FALSE;
492     }
493 
494     //-----------------------------------------------------------------------
495     /**
496      * Returns an <code>IOFileFilter</code> that wraps the
497      * <code>FileFilter</code> instance.
498      *
499      * @param filter  the filter to be wrapped
500      * @return a new filter that implements IOFileFilter
501      * @see DelegateFileFilter
502      */
503     public static IOFileFilter asFileFilter(final FileFilter filter) {
504         return new DelegateFileFilter(filter);
505     }
506 
507     /**
508      * Returns an <code>IOFileFilter</code> that wraps the
509      * <code>FilenameFilter</code> instance.
510      *
511      * @param filter  the filter to be wrapped
512      * @return a new filter that implements IOFileFilter
513      * @see DelegateFileFilter
514      */
515     public static IOFileFilter asFileFilter(final FilenameFilter filter) {
516         return new DelegateFileFilter(filter);
517     }
518 
519     //-----------------------------------------------------------------------
520     /**
521      * Returns a filter that returns true if the file was last modified after
522      * the specified cutoff time.
523      *
524      * @param cutoff  the time threshold
525      * @return an appropriately configured age file filter
526      * @see AgeFileFilter
527      * @since 1.2
528      */
529     public static IOFileFilter ageFileFilter(final long cutoff) {
530         return new AgeFileFilter(cutoff);
531     }
532 
533     /**
534      * Returns a filter that filters files based on a cutoff time.
535      *
536      * @param cutoff  the time threshold
537      * @param acceptOlder  if true, older files get accepted, if false, newer
538      * @return an appropriately configured age file filter
539      * @see AgeFileFilter
540      * @since 1.2
541      */
542     public static IOFileFilter ageFileFilter(final long cutoff, final boolean acceptOlder) {
543         return new AgeFileFilter(cutoff, acceptOlder);
544     }
545 
546     /**
547      * Returns a filter that returns true if the file was last modified after
548      * the specified cutoff date.
549      *
550      * @param cutoffDate  the time threshold
551      * @return an appropriately configured age file filter
552      * @see AgeFileFilter
553      * @since 1.2
554      */
555     public static IOFileFilter ageFileFilter(final Date cutoffDate) {
556         return new AgeFileFilter(cutoffDate);
557     }
558 
559     /**
560      * Returns a filter that filters files based on a cutoff date.
561      *
562      * @param cutoffDate  the time threshold
563      * @param acceptOlder  if true, older files get accepted, if false, newer
564      * @return an appropriately configured age file filter
565      * @see AgeFileFilter
566      * @since 1.2
567      */
568     public static IOFileFilter ageFileFilter(final Date cutoffDate, final boolean acceptOlder) {
569         return new AgeFileFilter(cutoffDate, acceptOlder);
570     }
571 
572     /**
573      * Returns a filter that returns true if the file was last modified after
574      * the specified reference file.
575      *
576      * @param cutoffReference  the file whose last modification
577      *        time is usesd as the threshold age of the files
578      * @return an appropriately configured age file filter
579      * @see AgeFileFilter
580      * @since 1.2
581      */
582     public static IOFileFilter ageFileFilter(final File cutoffReference) {
583         return new AgeFileFilter(cutoffReference);
584     }
585 
586     /**
587      * Returns a filter that filters files based on a cutoff reference file.
588      *
589      * @param cutoffReference  the file whose last modification
590      *        time is usesd as the threshold age of the files
591      * @param acceptOlder  if true, older files get accepted, if false, newer
592      * @return an appropriately configured age file filter
593      * @see AgeFileFilter
594      * @since 1.2
595      */
596     public static IOFileFilter ageFileFilter(final File cutoffReference, final boolean acceptOlder) {
597         return new AgeFileFilter(cutoffReference, acceptOlder);
598     }
599 
600     //-----------------------------------------------------------------------
601     /**
602      * Returns a filter that returns true if the file is bigger than a certain size.
603      *
604      * @param threshold  the file size threshold
605      * @return an appropriately configured SizeFileFilter
606      * @see SizeFileFilter
607      * @since 1.2
608      */
609     public static IOFileFilter sizeFileFilter(final long threshold) {
610         return new SizeFileFilter(threshold);
611     }
612 
613     /**
614      * Returns a filter that filters based on file size.
615      *
616      * @param threshold  the file size threshold
617      * @param acceptLarger  if true, larger files get accepted, if false, smaller
618      * @return an appropriately configured SizeFileFilter
619      * @see SizeFileFilter
620      * @since 1.2
621      */
622     public static IOFileFilter sizeFileFilter(final long threshold, final boolean acceptLarger) {
623         return new SizeFileFilter(threshold, acceptLarger);
624     }
625 
626     /**
627      * Returns a filter that accepts files whose size is &gt;= minimum size
628      * and &lt;= maximum size.
629      *
630      * @param minSizeInclusive the minimum file size (inclusive)
631      * @param maxSizeInclusive the maximum file size (inclusive)
632      * @return an appropriately configured IOFileFilter
633      * @see SizeFileFilter
634      * @since 1.3
635      */
636     public static IOFileFilter sizeRangeFileFilter(final long minSizeInclusive, final long maxSizeInclusive ) {
637         final IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true);
638         final IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false);
639         return new AndFileFilter(minimumFilter, maximumFilter);
640     }
641 
642     /**
643      * Returns a filter that accepts files that begin with the provided magic
644      * number.
645      *
646      * @param magicNumber the magic number (byte sequence) to match at the
647      *        beginning of each file.
648      *
649      * @return an IOFileFilter that accepts files beginning with the provided
650      *         magic number.
651      *
652      * @throws IllegalArgumentException if <code>magicNumber</code> is
653      *         {@code null} or the empty String.
654      * @see MagicNumberFileFilter
655      * @since 2.0
656      */
657     public static IOFileFilter magicNumberFileFilter(final String magicNumber) {
658         return new MagicNumberFileFilter(magicNumber);
659     }
660 
661     /**
662      * Returns a filter that accepts files that contains the provided magic
663      * number at a specified offset within the file.
664      *
665      * @param magicNumber the magic number (byte sequence) to match at the
666      *        provided offset in each file.
667      * @param offset the offset within the files to look for the magic number.
668      *
669      * @return an IOFileFilter that accepts files containing the magic number
670      *         at the specified offset.
671      *
672      * @throws IllegalArgumentException if <code>magicNumber</code> is
673      *         {@code null} or the empty String, or if offset is a
674      *         negative number.
675      * @see MagicNumberFileFilter
676      * @since 2.0
677      */
678     public static IOFileFilter magicNumberFileFilter(final String magicNumber, final long offset) {
679         return new MagicNumberFileFilter(magicNumber, offset);
680     }
681 
682     /**
683      * Returns a filter that accepts files that begin with the provided magic
684      * number.
685      *
686      * @param magicNumber the magic number (byte sequence) to match at the
687      *        beginning of each file.
688      *
689      * @return an IOFileFilter that accepts files beginning with the provided
690      *         magic number.
691      *
692      * @throws IllegalArgumentException if <code>magicNumber</code> is
693      *         {@code null} or is of length zero.
694      * @see MagicNumberFileFilter
695      * @since 2.0
696      */
697     public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber) {
698         return new MagicNumberFileFilter(magicNumber);
699     }
700 
701     /**
702      * Returns a filter that accepts files that contains the provided magic
703      * number at a specified offset within the file.
704      *
705      * @param magicNumber the magic number (byte sequence) to match at the
706      *        provided offset in each file.
707      * @param offset the offset within the files to look for the magic number.
708      *
709      * @return an IOFileFilter that accepts files containing the magic number
710      *         at the specified offset.
711      *
712      * @throws IllegalArgumentException if <code>magicNumber</code> is
713      *         {@code null}, or contains no bytes, or <code>offset</code>
714      *         is a negative number.
715      * @see MagicNumberFileFilter
716      * @since 2.0
717      */
718     public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber, final long offset) {
719         return new MagicNumberFileFilter(magicNumber, offset);
720     }
721 
722     //-----------------------------------------------------------------------
723     /* Constructed on demand and then cached */
724     private static final IOFileFilter cvsFilter = notFileFilter(
725             and(directoryFileFilter(), nameFileFilter("CVS")));
726 
727     /* Constructed on demand and then cached */
728     private static final IOFileFilter svnFilter = notFileFilter(
729             and(directoryFileFilter(), nameFileFilter(".svn")));
730 
731     /**
732      * Decorates a filter to make it ignore CVS directories.
733      * Passing in {@code null} will return a filter that accepts everything
734      * except CVS directories.
735      *
736      * @param filter  the filter to decorate, null means an unrestricted filter
737      * @return the decorated filter, never null
738      * @since 1.1 (method existed but had bug in 1.0)
739      */
740     public static IOFileFilter makeCVSAware(final IOFileFilter filter) {
741         if (filter == null) {
742             return cvsFilter;
743         } else {
744             return and(filter, cvsFilter);
745         }
746     }
747 
748     /**
749      * Decorates a filter to make it ignore SVN directories.
750      * Passing in {@code null} will return a filter that accepts everything
751      * except SVN directories.
752      *
753      * @param filter  the filter to decorate, null means an unrestricted filter
754      * @return the decorated filter, never null
755      * @since 1.1
756      */
757     public static IOFileFilter makeSVNAware(final IOFileFilter filter) {
758         if (filter == null) {
759             return svnFilter;
760         } else {
761             return and(filter, svnFilter);
762         }
763     }
764 
765     //-----------------------------------------------------------------------
766     /**
767      * Decorates a filter so that it only applies to directories and not to files.
768      *
769      * @param filter  the filter to decorate, null means an unrestricted filter
770      * @return the decorated filter, never null
771      * @see DirectoryFileFilter#DIRECTORY
772      * @since 1.3
773      */
774     public static IOFileFilter makeDirectoryOnly(final IOFileFilter filter) {
775         if (filter == null) {
776             return DirectoryFileFilter.DIRECTORY;
777         }
778         return new AndFileFilter(DirectoryFileFilter.DIRECTORY, filter);
779     }
780 
781     /**
782      * Decorates a filter so that it only applies to files and not to directories.
783      *
784      * @param filter  the filter to decorate, null means an unrestricted filter
785      * @return the decorated filter, never null
786      * @see FileFileFilter#FILE
787      * @since 1.3
788      */
789     public static IOFileFilter makeFileOnly(final IOFileFilter filter) {
790         if (filter == null) {
791             return FileFileFilter.FILE;
792         }
793         return new AndFileFilter(FileFileFilter.FILE, filter);
794     }
795 
796 }