2121import java .io .IOException ;
2222import java .util .Collection ;
2323
24+ import org .apache .commons .io .filefilter .FileFilterUtils ;
25+ import org .apache .commons .io .filefilter .IOFileFilter ;
26+ import org .apache .commons .io .filefilter .TrueFileFilter ;
27+
2428/**
2529 * Abstract class that walks through a directory hierarchy and provides
2630 * subclasses with convenient hooks to add specific behaviour.
8084 * <a name="filter"></a>
8185 * <h3>2. Filter Example</h3>
8286 *
83- * If you wanted all directories which are not hidden
84- * and files which end in ".txt" - you could build a composite filter
85- * using the filter implementations in the Commons IO
86- * <a href="filefilter/package-summary.html">filefilter</a> package
87- * in the following way:
88- *
87+ * Choosing which directories and files to process can be a key aspect
88+ * of using this class. This information can be setup in three ways,
89+ * via three different constructors.
90+ * <p>
91+ * The first option is to visit all directories and files.
92+ * This is achieved via the no-args constructor.
93+ * <p>
94+ * The second constructor option is to supply a single {@link FileFilter}
95+ * that describes the files and directories to visit. Care must be taken
96+ * with this option as the same filter is used for both directories
97+ * and files.
98+ * <p>
99+ * For example, if you wanted all directories which are not hidden
100+ * and files which end in ".txt":
89101 * <pre>
90- *
102+ * public class FooDirectoryWalker extends DirectoryWalker {
103+ * public FooDirectoryWalker(FileFilter filter) {
104+ * super(filter, -1);
105+ * }
106+ * }
107+ *
108+ * // Build up the filters and create the walker
91109 * // Create a filter for Non-hidden directories
92110 * IOFileFilter fooDirFilter =
93111 * FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
103121 * FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
104122 *
105123 * // Use the filter to construct a DirectoryWalker implementation
106- * FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter, -1);
107- *
124+ * FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
108125 * </pre>
126+ * <p>
127+ * The third constructor option is to specify separate filters, one for
128+ * directories and one for files. These are combined internally to form
129+ * the correct <code>FileFilter</code>, something which is very easy to
130+ * get wrong when attempted manually, particularly when trying to
131+ * express constructs like 'any file in directories named docs'.
132+ * <p>
133+ * For example, if you wanted all directories which are not hidden
134+ * and files which end in ".txt":
135+ * <pre>
136+ * public class FooDirectoryWalker extends DirectoryWalker {
137+ * public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
138+ * super(dirFilter, fileFilter, -1);
139+ * }
140+ * }
141+ *
142+ * // Use the filters to construct the walker
143+ * FooDirectoryWalker walker = new FooDirectoryWalker(
144+ * HiddenFileFilter.VISIBLE,
145+ * FileFilterUtils.suffixFileFilter(".txt"),
146+ * );
147+ * <pre>
148+ * This is much simpler than the previous example, and is why it is the preferred
149+ * option for filtering.
109150 *
110151 * <a name="cancel"></a>
111152 * <h3>3. Cancellation</h3>
145186 *
146187 * This example provides a <code>cancel()</code> method for external processes to
147188 * indcate that processing must stop. Calling this method sets a
148- * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930">
149- * volatile</a> flag to (hopefully) ensure it will work properly in
189+ * <a href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#36930">volatile</a>
190+ * flag to (hopefully) ensure it will work properly in
150191 * a multi-threaded environment. In this implementation the flag is checked in two
151192 * of the lifecycle methods using a convenience <code>checkIfCancelled()</code> method
152193 * which throws a {@link CancelException} if cancellation has been requested.
@@ -237,8 +278,13 @@ protected DirectoryWalker() {
237278
238279 /**
239280 * Construct an instance with a filter and limit the <i>depth</i> navigated to.
281+ * <p>
282+ * The filter controls which files and directories will be navigated to as
283+ * part of the walk. The {@link FileFilterUtils} class is useful for combining
284+ * various filters together. A <code>null</code> filter means that no
285+ * filtering should occur and all files and directories will be visited.
240286 *
241- * @param filter the filter to limit the navigation/results, may be null
287+ * @param filter the filter to apply, null means visit all files
242288 * @param depthLimit controls how <i>deep</i> the hierarchy is
243289 * navigated to (less than 0 means unlimited)
244290 */
@@ -247,6 +293,33 @@ protected DirectoryWalker(FileFilter filter, int depthLimit) {
247293 this .depthLimit = depthLimit ;
248294 }
249295
296+ /**
297+ * Construct an instance with a directory and a file filter and an optional
298+ * limit on the <i>depth</i> navigated to.
299+ * <p>
300+ * The filters control which files and directories will be navigated to as part
301+ * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly()}
302+ * and {@link FileFilterUtils#makeFileOnly()} internally to combine the filters.
303+ * A <code>null</code> filter means that no filtering should occur.
304+ *
305+ * @param directoryFilter the filter to apply to directories, null means visit all directories
306+ * @param fileFilter the filter to apply to files, null means visit all files
307+ * @param depthLimit controls how <i>deep</i> the hierarchy is
308+ * navigated to (less than 0 means unlimited)
309+ */
310+ protected DirectoryWalker (IOFileFilter directoryFilter , IOFileFilter fileFilter , int depthLimit ) {
311+ if (directoryFilter == null && fileFilter == null ) {
312+ this .filter = null ;
313+ } else {
314+ directoryFilter = (directoryFilter != null ? directoryFilter : TrueFileFilter .TRUE );
315+ fileFilter = (fileFilter != null ? fileFilter : TrueFileFilter .TRUE );
316+ directoryFilter = FileFilterUtils .makeDirectoryOnly (directoryFilter );
317+ fileFilter = FileFilterUtils .makeFileOnly (fileFilter );
318+ this .filter = FileFilterUtils .orFileFilter (directoryFilter , fileFilter );
319+ }
320+ this .depthLimit = depthLimit ;
321+ }
322+
250323 //-----------------------------------------------------------------------
251324 /**
252325 * Internal method that walks the directory hierarchy in a depth-first manner.
0 commit comments