2020import java .util .List ;
2121import java .util .ArrayList ;
2222
23+ import org .apache .commons .io .filefilter .FileFilterUtils ;
24+ import org .apache .commons .io .filefilter .IOFileFilter ;
25+
2326/**
24- * <p>Navigate/search through a File Hierarchy.</p>
25- *
26- * <p>FileFinder can be used as it is to provide a list
27- * of the files and directories in a file hierarchy,
28- * starting from a specified point.</p>
29- *
30- * <p>It can be used in conjunction with a <code>FileFilter</code>
31- * to selectively filter the results produced. Commons IO
32- * provides a number of useful
33- * {@link org.apache.commons.io.filefilter.IOFileFilter} implementations
34- * which can be used in conjunction with this class.</p>
35- *
36- * <p>FileFinder can also be extended to provide custom implementations
37- * that process the file hierarchy further (see example file cleaner below).</p>
27+ * Finds files in a directory hierarchy, with the potential for subclasses
28+ * to add additiional behaviour.
29+ * <p>
30+ * FileFinder can be used without changes to provide a list of the files
31+ * and directories in a file hierarchy starting from a specified point.
32+ * This list can be filtered by hierarchy depth and using a
33+ * {@link IOFileFilter file filter}.
34+ * <p>
35+ * Commons IO supplies many common filter implementations in the
36+ * <code>filefilter</code> package, see {@link FileFilterUtils}.
37+ * You can also create your own custom implementation, such as in the
38+ * file cleaner example below.
3839 *
3940 * <h4>Example 1 - List all files and directories</h4>
40- * <p>Example, showing how to list all files and directories
41- * starting from the current directory:</p>
42- *
41+ * Example, showing how to list all files and directories starting from
42+ * the current directory:
4343 * <pre>
4444 * List files = FileFinder.ALL_FILES.find();
4545 * for (int i = 0; i < files.size(); i++) {
4949 * </pre>
5050 *
5151 * <h4>Example 2 - Filtered list of files and directories</h4>
52- * <p>Example, showing how to list all directories and
53- * files ending in ".java" starting in a directory called
54- * "src":</p>
55- *
52+ * Example, showing how to list all files ending in ".java" starting in
53+ * a directory called "src":
5654 * <pre>
57- * IOFileFilter dirFilter = DirectoryFileFilter.INSTANCE ;
58- * IOFileFilter fileFilter = new SuffixFileFilter(".java");
59- * IOFileFilter filter = new OrFileFilter(directories, txtFiles );
55+ * IOFileFilter filesFilter = FileFileFilter.FILE ;
56+ * IOFileFilter javaFilter = new SuffixFileFilter(".java");
57+ * IOFileFilter filter = new AndFileFilter(filesFilter, javaFilter );
6058 *
6159 * FileFinder finder = new FileFinder(filter);
6260 *
6866 * </pre>
6967 *
7068 * <h4>Example 3 - Custom Implementation</h4>
71- * <p>Example, showing how to create an implementation that
72- * deletes files and directories and returns a list of
73- * what has been deleted.</p>
69+ * Example, showing how to create an implementation that deletes files
70+ * and directories and returns a list of what has been deleted.
7471 *
7572 * <pre>
7673 * public class FileDelete extends FileFinder {
7774 *
78- * public FileDelete() {
79- * }
80- *
81- * protected void handleDirectoryStart(File directory, int depth, List results) {
82- * }
75+ * public FileDelete() {
76+ * }
8377 *
84- * protected void handleDirectoryEnd(File directory, int depth, List results) {
85- * directory.delete();
86- * results.add(directory);
87- * }
78+ * protected void handleDirectoryStart(File directory, int depth, List results) {
79+ * }
8880 *
89- * protected void handleFile(File file, int depth, List results) {
90- * file.delete();
91- * results.add(file);
92- * }
81+ * protected void handleDirectoryEnd(File directory, int depth, List results) {
82+ * directory.delete();
83+ * results.add(directory);
84+ * }
85+ *
86+ * protected void handleFile(File file, int depth, List results) {
87+ * file.delete();
88+ * results.add(file);
89+ * }
9390 * }
9491 * </pre>
9592 *
@@ -111,54 +108,55 @@ protected FileFinder() {
111108 }
112109
113110 /**
114- * <p> Construct an instance with a filter.</p>
111+ * Construct an instance with a filter.
115112 *
116- * @param filter Filter to limit the navigation/results
113+ * @param filter the filter to limit the navigation/results
117114 */
118115 public FileFinder (FileFilter filter ) {
119116 this (filter , -1 );
120117 }
121118
122119 /**
123- * <p>Construct an instance limiting the <i>depth</i>
124- * navigated to.</p>
120+ * Construct an instance limiting the <i>depth</i> navigated to.
125121 *
126- * @param depthLimit Controls how <i>deep</i> the hierarchy is
122+ * @param depthLimit cntrols how <i>deep</i> the hierarchy is
127123 * navigated to (less than 0 means unlimited)
128124 */
129125 public FileFinder (int depthLimit ) {
130126 this (null , depthLimit );
131127 }
132128
133129 /**
134- * <p>Construct an instance with a filter and limit
135- * the <i>depth</i> navigated to.</p>
130+ * Construct an instance with a filter and limit the <i>depth</i> navigated to.
136131 *
137- * @param filter Filter to limit the navigation/results
138- * @param depthLimit Controls how <i>deep</i> the hierarchy is
132+ * @param filter the filter to limit the navigation/results
133+ * @param depthLimit controls how <i>deep</i> the hierarchy is
139134 * navigated to (less than 0 means unlimited)
140135 */
141136 public FileFinder (FileFilter filter , int depthLimit ) {
142137 this .filter = filter ;
143138 this .depthLimit = depthLimit ;
144139 }
145140
141+ //-----------------------------------------------------------------------
146142 /**
147- * <p>Walk the file hierarchy starting from the current
148- * directory.</p>
143+ * Finds all the files and directories in the directory hierarchy starting
144+ * from the current directory.
149145 *
150- * @return The collection of files found.
146+ * @return the collection of files found
151147 */
152148 public List find () {
153149 return find (new File ("." ));
154150 }
155151
156152 /**
157- * <p>Walk the file hierarchy starting from the specified
158- * directory.</p>
153+ * Finds all the files and directories in the directory hierarchy starting
154+ * from the specified directory.
159155 *
160- * @param startDirectory The directory to start from
161- * @return The collection of files found.
156+ * @param startDirectory the directory to start from, must be valid
157+ * @return the collection of files found
158+ * @throws IllegalArgumentException if the start directory is null,
159+ * doesn't exist or isn't a directory
162160 */
163161 public List find (File startDirectory ) {
164162 if (startDirectory == null || !startDirectory .exists ()) {
@@ -169,84 +167,130 @@ public List find(File startDirectory) {
169167 String message = "Not a directory: " + startDirectory ;
170168 throw new IllegalArgumentException (message );
171169 }
170+ return examine (startDirectory );
171+ }
172+
173+ //-----------------------------------------------------------------------
174+ /**
175+ * Examines the directory hierarchy.
176+ *
177+ * @param startDirectory the directory to start from
178+ * @return the collection of result objects
179+ */
180+ private List examine (File startDirectory ) {
172181 List results = new ArrayList ();
173- handleDirectory (startDirectory , 0 , results );
182+ handleStart (startDirectory , results );
183+ examine (startDirectory , 0 , results );
184+ handleEnd (results );
174185 return results ;
175186 }
176187
177188 /**
178- * <p>Process a directory.</p>
189+ * Main recursive method to examine the directory hierarchy.
179190 *
180- * @param directory The directory to process
181- * @param depth The directory level (starting directory = 0)
182- * @param results The collection of files found.
191+ * @param directory the directory to examine
192+ * @param depth the directory level (starting directory = 0)
193+ * @return the collection of result objects
183194 */
184- private void handleDirectory (File directory , int depth , List results ) {
185- handleDirectoryStart (directory , depth , results );
186- int childDepth = depth + 1 ;
187- if (depthLimit < 0 || childDepth <= depthLimit ) {
188- File [] files = (filter == null ? directory .listFiles () : directory .listFiles (filter ));
189- if (files == null ) {
190- handleRestricted (directory );
191- } else {
192- for (int i = 0 ; i < files .length ; i ++) {
193- if (files [i ].isDirectory ()) {
194- handleDirectory (files [i ], childDepth , results );
195- } else {
196- handleFile (files [i ], childDepth , results );
195+ private void examine (File directory , int depth , List results ) {
196+ boolean process = handleDirectoryStart (directory , depth , results );
197+ if (process ) {
198+ int childDepth = depth + 1 ;
199+ if (depthLimit < 0 || childDepth <= depthLimit ) {
200+ File [] files = (filter == null ? directory .listFiles () : directory .listFiles (filter ));
201+ if (files == null ) {
202+ handleRestricted (directory );
203+ } else {
204+ for (int i = 0 ; i < files .length ; i ++) {
205+ if (files [i ].isDirectory ()) {
206+ examine (files [i ], childDepth , results );
207+ } else {
208+ handleFile (files [i ], childDepth , results );
209+ }
197210 }
198211 }
199212 }
200213 }
201214 handleDirectoryEnd (directory , depth , results );
202215 }
203216
217+ //-----------------------------------------------------------------------
204218 /**
205- * <p>Initial directory processing.</p>
219+ * Overridable callback method invoked at the start of processing.
220+ * <p>
221+ * This implementation does nohting.
206222 *
207- * <p>This implementation adds the directory to the
208- * results collection.</p>
223+ * @param startDirectory the directory to start from
224+ * @param results the collection of result objects, may be updated
225+ */
226+ protected void handleStart (File startDirectory , List results ) {
227+ // do nothing - overridable by subclass
228+ }
229+
230+ /**
231+ * Overridable callback method invoked at the start of processing each directory.
232+ * <p>
233+ * This method returns a boolean to indicate if the directory should be examined
234+ * or not. If you return false, the next event received will be the
235+ * {@link #handleDirectoryEnd} for that directory. Note that this functionality
236+ * is in addition to the filtering by file filter.
237+ * <p>
238+ * This implementation adds the directory to the results collection.
209239 *
210- * @param directory The directory being processed
211- * @param depth The directory level (starting directory = 0)
212- * @param results The collection of files found.
240+ * @param directory the current directory being processed
241+ * @param depth the current directory level (starting directory = 0)
242+ * @param results the collection of result objects, may be updated
243+ * @return true to process this directory, false to skip this directory
213244 */
214- protected void handleDirectoryStart (File directory , int depth , List results ) {
245+ protected boolean handleDirectoryStart (File directory , int depth , List results ) {
215246 results .add (directory );
247+ return true ;
216248 }
217249
218250 /**
219- * <p>Final directory processing.</p>
220- *
221- * <p> This implementation does nothing.</p>
251+ * Overridable callback method invoked for each (non- directory) file.
252+ * <p>
253+ * This implementation adds the file to the results collection.
222254 *
223- * @param directory The directory being processed
224- * @param depth The directory level (starting directory = 0)
225- * @param results The collection of files found.
255+ * @param file the current file being processed
256+ * @param depth the current directory level (starting directory = 0)
257+ * @param results the collection of result objects, may be updated
226258 */
227- protected void handleDirectoryEnd (File directory , int depth , List results ) {
259+ protected void handleFile (File file , int depth , List results ) {
260+ results .add (file );
228261 }
229262
263+ /**
264+ * Overridable callback method invoked for each restricted directory.
265+ *
266+ * @param directory the restricted directory
267+ */
268+ protected void handleRestricted (File directory ) {
269+ // do nothing - overridable by subclass
270+ }
230271
231272 /**
232- * <p>File processing.</p>
233- *
234- * <p>This implementation adds the file to the results
235- * collection.</p>
273+ * Overridable callback method invoked at the end of processing each directory.
274+ * <p>
275+ * This implementation does nothing.
236276 *
237- * @param file The file being processed
277+ * @param directory The directory being processed
238278 * @param depth The directory level (starting directory = 0)
239279 * @param results The collection of files found.
240280 */
241- protected void handleFile (File file , int depth , List results ) {
242- results . add ( file );
281+ protected void handleDirectoryEnd (File directory , int depth , List results ) {
282+ // do nothing - overridable by subclass
243283 }
244284
245285 /**
246- * <p>Handle directories which are restricted.</p>
247- *
248- * @param directory Restricted directory
286+ * Overridable callback method invoked at the end of processing.
287+ * <p>
288+ * This implementation does nothing.
289+ *
290+ * @param results the collection of result objects, may be updated
249291 */
250- protected void handleRestricted (File directory ) {
292+ protected void handleEnd (List results ) {
293+ // do nothing - overridable by subclass
251294 }
252- }
295+
296+ }
0 commit comments