View Javadoc

1   package com.explosion.utilities;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import com.explosion.utilities.regex.RegExpFileAndDirectoryFilter;
9   import com.explosion.utilities.regex.RegExpFileNameFilter;
10  
11  /*
12   * =============================================================================
13   * 
14   * Copyright 2004 Stephen Cowx
15   * 
16   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
17   * use this file except in compliance with the License. You may obtain a copy of
18   * the License at
19   * 
20   * http://www.apache.org/licenses/LICENSE-2.0
21   * 
22   * Unless required by applicable law or agreed to in writing, software
23   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25   * License for the specific language governing permissions and limitations under
26   * the License.
27   * 
28   * =============================================================================
29   */
30  
31  /***
32   * A really handy class which will pass back to you all the files in a directory
33   * recursively one at a time whenever one is asked for.
34   * 
35   * @author Stephen Created on May 5, 2004
36   */
37  public class FileIterator
38  {
39  
40      //private static Logger log = LogManager.getLogger(FileIterator.class);
41      
42      private boolean recursive = false;
43      private boolean excludeDirectories = true;
44      private boolean caseSensitive = false;
45      private boolean hasNext = true;
46      
47      private String fileNamePattern = null;
48      private RegExpFileAndDirectoryFilter regExpAndDirectoryFilter;
49      private RegExpFileNameFilter regExpFilter;
50      private List fileList = new ArrayList();
51      private FileIterator activeIterator;
52      private File currentFile = null;
53      private File fileToReturn = null;
54      
55      private int index = 0;
56      private int recursionLevel = 0;
57      private int numberOfFiles = 0;
58      private int numberOfDirectories = 0;
59  
60      /***
61       * Creates a file iterator object with the provided arguments
62       * @param directory directory to look in
63       * @param pattern regexp pattern of filename to look for
64       * @param caseSensitive regexp matching to be case sensitive or not
65       * @param recursive find files recursively
66       * @param excludesDirectories will not return any directories if set to true
67       */
68      public FileIterator(String directory, String fileNamePattern, boolean caseSensitive, boolean recursive, boolean excludeDirectories) throws IOException
69      {
70          this.recursive = recursive;
71          this.caseSensitive = caseSensitive;
72          this.excludeDirectories = excludeDirectories;
73          this.fileNamePattern = (fileNamePattern == null ? "" : fileNamePattern);
74          regExpFilter = new RegExpFileNameFilter(fileNamePattern, caseSensitive);
75          File sourceDirectory = new File(directory);
76  
77          /* Checking */
78          if (!sourceDirectory.exists())
79              throw new IOException("Unable to find path specified for creating a list of files: " + directory);
80  
81          if (!sourceDirectory.isDirectory())
82              throw new IOException("Path specified for creating a list of files is not a directory : " + directory);
83  
84          if (!recursive && excludeDirectories)
85          {
86              /* Initilaise the regExpAndDirectoryFilter */
87              regExpAndDirectoryFilter = new RegExpFileAndDirectoryFilter(regExpFilter);
88              File[] files = sourceDirectory.listFiles(regExpAndDirectoryFilter);
89              for (int i = 0; i < files.length; i++)
90                  fileList.add(files[i]);
91  
92             // log.debug(getRecursionLevelString() + "New iterator for [" + sourceDirectory + "] contains " + fileList);
93          }
94          else
95          {
96              File[] files = sourceDirectory.listFiles();
97              for (int i = 0; i < files.length; i++)
98              {
99                  if (files[i].isDirectory() || regExpFilter.accept(files[i].getParentFile(), files[i].getName()))
100                 {
101                     fileList.add(files[i]);
102                     if (files[i].isDirectory())
103                         numberOfDirectories++;
104                     else
105                         numberOfFiles++;
106                 }
107             }
108            // log.debug(getRecursionLevelString() + "New iterator for [" + sourceDirectory + "] contains " + fileList);
109         }
110         
111         /* Initialise currentFile  */
112         if (fileList.size() > 0)
113         {
114             index = 0;
115             currentFile = (File) fileList.get(index);
116         }
117     }
118 
119     /***
120      * Returns a boolean stating whether there are any more files in the
121      * iterator.
122      * 
123      * @return
124      */
125     public boolean hasNext() throws IOException
126     {
127         if (currentFile == null)
128             return false;
129         else
130         {
131           fileToReturn = getNext();
132           return fileToReturn != null;
133         }
134     }
135 
136     public File getNext() throws IOException
137     {
138         if (currentFile.isDirectory())
139         {
140             if (recursive)
141             {
142                /* First return all of the files in this directoy and then return return the directory itself if !exclude directories */
143                
144                /* 1.) We need an iterator for the files in this directory */
145                if (activeIterator == null)
146                {
147                   activeIterator = new FileIterator(currentFile.getAbsolutePath(), fileNamePattern, caseSensitive, recursive, excludeDirectories);
148                   activeIterator.recursionLevel=recursionLevel++;
149                }
150                
151                /* If this directory has any files/directories in it then we want to return all of them first */
152                if (activeIterator.hasNext())
153                {
154                    return activeIterator.next();  
155                }
156                else
157                {
158                    /* Null the activeIterator so that it will reinitialise a new one for the next directory we find */
159                    activeIterator = null;
160                    
161                    /* Otherwise we want to return this directory if !excludeDirectories  or we want to start everything all over again with the next file in this iterator*/
162                    if (excludeDirectories)
163                    {
164                        /* Move on to the next file */
165                        transitionIterator();
166                        if (currentFile == null)
167                        {
168                            /* There are no more files */
169                            return null;
170                        }
171                        else
172                        {
173                            /* Scan until we find one */
174                            return getNext();
175                        }
176                    }
177                    else
178                    {
179                        /* It is safe to fall down to the bottom and return the current file */
180                    }
181                }
182             }
183             else
184             {
185                 /* If it is not recursive and this is a directory then exclude directories must be false */
186                 //assert excludeDirectories == false : "Expected excludeDirectories to be false but it was true";
187                 /* It is safe to fall down to the bottom and return the current file */
188             }
189         }
190         
191         File returnValue = currentFile;
192         transitionIterator();
193         //log.debug(getRecursionLevelString() + "Found file " + returnValue);
194         return returnValue;        
195     }
196     
197     private String getRecursionLevelString()
198     {
199         String string = new String();
200         for (int i=0;i<recursionLevel;i++)
201         {
202             string += "   ";
203         }
204         return string;
205     }
206     
207     /***
208      * This method incremenets the iterator and looks after the 
209      * index, hasNext and currentFile variables  
210      *
211      */
212     private void transitionIterator()
213     {
214         index++;
215         if (index < fileList.size())
216         {
217             /* this means that there are still more files / directories to come */
218             currentFile = (File) fileList.get(index);
219         }
220         else
221         {
222             currentFile = null;
223         }
224     }
225     
226     /***
227      * Returns the next file in this iterator
228      * 
229      * @return
230      */
231     public File next() throws IOException
232     {
233         return fileToReturn;
234     }
235     
236     /***
237      * At best a rough guide.  It basically just gives you the result of the progress through the top level of files.
238      * @return int percent complete
239      */
240     public int getPercentComplete()
241     {
242         if (fileList.size() == 0) 
243           return 100;
244         else
245           return ( index / fileList.size() ) * 100;
246     }
247 
248     /***
249      * @return Returns the caseSensitive.
250      */
251     public boolean isCaseSensitive()
252     {
253         return caseSensitive;
254     }
255     /***
256      * @return Returns the excludeDirectories.
257      */
258     public boolean isExcludeDirectories()
259     {
260         return excludeDirectories;
261     }
262     /***
263      * @return Returns the numberOfDirectories.
264      */
265     public int getNumberOfDirectories()
266     {
267         return numberOfDirectories;
268     }
269     /***
270      * @return Returns the numberOfFiles.
271      */
272     public int getNumberOfFiles()
273     {
274         return numberOfFiles;
275     }
276     
277     /***
278      * Returns the total number of items in this iterator
279      * @return
280      */
281     public int getNumberOfItems()
282     {
283         return fileList.size();
284     }
285     /***
286      * @return Returns the recursive.
287      */
288     public boolean isRecursive()
289     {
290         return recursive;
291     }
292 }