Skip to content

Commit 1d4766b

Browse files
author
Stephen Colebourne
committed
Allow subclasses to block skip directory processing
Add start and end callback methods Improve documentation git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/io/trunk@424748 13f79535-47bb-0310-9956-ffa450edef68
1 parent c112e3b commit 1d4766b

1 file changed

Lines changed: 144 additions & 100 deletions

File tree

src/java/org/apache/commons/io/FileFinder.java

Lines changed: 144 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,26 @@
2020
import java.util.List;
2121
import 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++) {
@@ -49,14 +49,12 @@
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
*
@@ -68,28 +66,27 @@
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

Comments
 (0)