1+ /*
2+ * Copyright 2005-2006 The Apache Software Foundation.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package org .apache .commons .io ;
17+
18+ import java .io .File ;
19+ import java .io .FileFilter ;
20+ import java .util .List ;
21+ import java .util .ArrayList ;
22+
23+ /**
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>
38+ *
39+ * <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+ *
43+ * <pre>
44+ * List files = FileFinder.ALL_FILES.find();
45+ * for (int i = 0; i < files.size(); i++) {
46+ * File file = (File)files.get(i);
47+ * System.out.println(file.getName());
48+ * }
49+ * </pre>
50+ *
51+ * <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+ *
56+ * <pre>
57+ * IOFileFilter dirFilter = DirectoryFileFilter.INSTANCE;
58+ * IOFileFilter fileFilter = new SuffixFileFilter(".java");
59+ * IOFileFilter filter = new OrFileFilter(directories, txtFiles);
60+ *
61+ * FileFinder finder = new FileFinder(filter);
62+ *
63+ * List files = finder.find(new File("src"));
64+ * for (int i = 0; i < files.size(); i++) {
65+ * File file = (File)files.get(i);
66+ * System.out.println(file.getName());
67+ * }
68+ * </pre>
69+ *
70+ * <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>
74+ *
75+ * <pre>
76+ * public class FileDelete extends FileFinder {
77+ *
78+ * public FileDelete() {
79+ * }
80+ *
81+ * protected void handleDirectoryStart(File directory, int depth, List results) {
82+ * }
83+ *
84+ * protected void handleDirectoryEnd(File directory, int depth, List results) {
85+ * directory.delete();
86+ * results.add(directory);
87+ * }
88+ *
89+ * protected void handleFile(File file, int depth, List results) {
90+ * file.delete();
91+ * results.add(file);
92+ * }
93+ * }
94+ * </pre>
95+ *
96+ * @since Commons IO 1.3
97+ * @version $Revision$
98+ */
99+ public class FileFinder {
100+
101+ /** Singleton instance that finds all files */
102+ public static final FileFinder ALL_FILES = new FileFinder ();
103+
104+ private FileFilter filter ;
105+ private int depthLimit = -1 ;
106+
107+ /**
108+ * Restrictive consructor - use <code>ALL_FILES</code> singleton instance.
109+ */
110+ protected FileFinder () {
111+ }
112+
113+ /**
114+ * <p>Construct an instance with a filter.</p>
115+ *
116+ * @param filter Filter to limit the navigation/results
117+ */
118+ public FileFinder (FileFilter filter ) {
119+ this (filter , -1 );
120+ }
121+
122+ /**
123+ * <p>Construct an instance limiting the <i>depth</i>
124+ * navigated to.</p>
125+ *
126+ * @param depthLimit Controls how <i>deep</i> the hierarchy is
127+ * navigated to (less than 0 means unlimited)
128+ */
129+ public FileFinder (int depthLimit ) {
130+ this (null , depthLimit );
131+ }
132+
133+ /**
134+ * <p>Construct an instance with a filter and limit
135+ * the <i>depth</i> navigated to.</p>
136+ *
137+ * @param filter Filter to limit the navigation/results
138+ * @param depthLimit Controls how <i>deep</i> the hierarchy is
139+ * navigated to (less than 0 means unlimited)
140+ */
141+ public FileFinder (FileFilter filter , int depthLimit ) {
142+ this .filter = filter ;
143+ this .depthLimit = depthLimit ;
144+ }
145+
146+ /**
147+ * <p>Walk the file hierarchy starting from the current
148+ * directory.</p>
149+ *
150+ * @return The collection of files found.
151+ */
152+ public List find () {
153+ return find (new File ("." ));
154+ }
155+
156+ /**
157+ * <p>Walk the file hierarchy starting from the specified
158+ * directory.</p>
159+ *
160+ * @param startDirectory The directory to start from
161+ * @return The collection of files found.
162+ */
163+ public List find (File startDirectory ) {
164+ if (startDirectory == null || !startDirectory .exists ()) {
165+ String message = "Directory does not exist: " + startDirectory ;
166+ throw new IllegalArgumentException (message );
167+ }
168+ if (!startDirectory .isDirectory ()) {
169+ String message = "Not a directory: " + startDirectory ;
170+ throw new IllegalArgumentException (message );
171+ }
172+ List results = new ArrayList ();
173+ handleDirectory (startDirectory , 0 , results );
174+ return results ;
175+ }
176+
177+ /**
178+ * <p>Process a directory.</p>
179+ *
180+ * @param directory The directory to process
181+ * @param depth The directory level (starting directory = 0)
182+ * @param results The collection of files found.
183+ */
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 );
197+ }
198+ }
199+ }
200+ }
201+ handleDirectoryEnd (directory , depth , results );
202+ }
203+
204+ /**
205+ * <p>Initial directory processing.</p>
206+ *
207+ * <p>This implementation adds the directory to the
208+ * results collection.</p>
209+ *
210+ * @param directory The directory being processed
211+ * @param depth The directory level (starting directory = 0)
212+ * @param results The collection of files found.
213+ */
214+ protected void handleDirectoryStart (File directory , int depth , List results ) {
215+ results .add (directory );
216+ }
217+
218+ /**
219+ * <p>Final directory processing.</p>
220+ *
221+ * <p>This implementation does nothing.</p>
222+ *
223+ * @param directory The directory being processed
224+ * @param depth The directory level (starting directory = 0)
225+ * @param results The collection of files found.
226+ */
227+ protected void handleDirectoryEnd (File directory , int depth , List results ) {
228+ }
229+
230+
231+ /**
232+ * <p>File processing.</p>
233+ *
234+ * <p>This implementation adds the file to the results
235+ * collection.</p>
236+ *
237+ * @param file The file being processed
238+ * @param depth The directory level (starting directory = 0)
239+ * @param results The collection of files found.
240+ */
241+ protected void handleFile (File file , int depth , List results ) {
242+ results .add (file );
243+ }
244+
245+ /**
246+ * <p>Handle directories which are restricted.</p>
247+ *
248+ * @param directory Restricted directory
249+ */
250+ protected void handleRestricted (File directory ) {
251+ }
252+ }
0 commit comments