You have a directory and you need to retrieve all files of a certain type in all directories below.
By binding an asynchronously updated ArrayCollection to a DataGrids dataProvider you can see all the files that are found as soon as the operating system returns them. Each time you discover a directory you asynchronously request a directory listing and respond in its handler by iterating over the result and doing the same with each subsequent directory discovered down through the tree.
I'll demonstrate this technique in a simple application that allows the user to select a start directory and up to 3 video file extensions to search for.
Start with some simple MXML to create the user interface:
<mx:Label top="10" left="10" text="Search for files of type:"/>
<mx:CheckBox x="10" y="36" label="AVI" id="avi_chk" />
<mx:CheckBox x="66" y="36" label="MPG" id="mpg_chk" />
<mx:CheckBox x="123" y="36" label="FLV" id="flv_chk" />
<mx:Button id="browse_btn" right="10" y="36" label="Browse" click="openDirectorySelection()" />
<mx:Label left="180" y="10" text="Search Within:" width="240"/>
<mx:TextInput id="directory_txt" right="90" left="180" y="36" />
<mx:Button x="10" y="68" label="search" click="search()" enabled="false" id="search_btn" />
<mx:Text y="70" left="90" right="10" id="searching_txt" />
<mx:DataGrid top="110" left="10" bottom="40" right="10" dataProvider="{filesFound}" >
<mx:columns>
<mx:DataGridColumn headerText="name" dataField="name"/>
<mx:DataGridColumn headerText="location" dataField="nativePath"/>
<mx:DataGridColumn headerText="type" dataField="extension"/>
<mx:DataGridColumn headerText="size (bytes) " dataField="size"/>
</mx:columns>
</mx:DataGrid>
<mx:ButtonBar id="controls_btnbar" right="10" bottom="10" itemClick="onButtonBarItemClick( event )">
<mx:dataProvider>
<mx:String>stop</mx:String>
<mx:String>pause</mx:String>
<mx:String>play</mx:String>
</mx:dataProvider>
</mx:ButtonBar>
This includes:
The user begins by selecting the file extensions he wished to search for and then selects a start directory in using the browse button.
Once the user has done this they are ready to search. Clicking the Search button will return all the results to your data grid asynchronously when the OS returns.
The core code required for searching in the manner is short and simple:
/**
* Start the search
*/
public function search () : void
{
search_btn.enabled = false;
try
{
if ( startDirectory.nativePath != directory_txt.text )
{
startDirectory = startDirectory.resolvePath( directory_txt.text );
}
pendingFileListings.addItem( startDirectory );
startDirectory.addEventListener( FileListEvent.DIRECTORY_LISTING, directoryListingHandler );
startDirectory.addEventListener( IOErrorEvent.IO_ERROR, onIOError );
startDirectory.getDirectoryListingAsync();
ButtonBarButton( controls_btnbar.getChildAt(0) ).enabled = true;
ButtonBarButton( controls_btnbar.getChildAt(1) ).enabled = true;
}
catch ( e:Error )
{
search_btn.enabled = true;
Alert.show( e.message );
}
/**
* Fired when the result of an asynchronous directory listing is returned
*
* @param e the FileListEvent object
*/
private function directoryListingHandler ( e:FileListEvent ) : void
{
pendingFileListings.removeItemAt( pendingFileListings.getItemIndex( e.target ) );
e.target.removeEventListener( FileListEvent.DIRECTORY_LISTING, directoryListingHandler );
e.files.forEach( checkExtensions );
}
/**
* The array iterator function for the listing of each directory found
*
* @param file The file object being looked into
* @param index The index of the file in the result array from the listings call
* @param arr The original Array
*/
private function checkExtensions ( file:File, index:int, arr:Array ) : void
{
if ( file.isDirectory )
{
pendingFileListings.addItem( file );
file.addEventListener(FileListEvent.DIRECTORY_LISTING, directoryListingHandler);
file.getDirectoryListingAsync();
}
else
{
if ( file.exists )
{
searching_txt.text = file.nativePath;
for ( var i:int=extensions.length; i--; )
{
if ( file.extension!=null && file.extension.toUpperCase() == extensions[i] )
{
// add this one to the datagrid
filesFound.addItem( file )
break;
}
}
}
}
}
The search method takes the start directory and asynchronously requests the directory listing from the operating system. The directoryListingHandler is fired when it comes back.
First, remove the listing event listener from the target that has just triggerred the event, for each File object in the result set we run the checkExtensions method. If the File object is a directory, start the loop again by requesting the listing and handling the result in directoryListingHandler. If the result is a file object, check its extension. If it's a match, add it to the filesFound ArrayCollection which is bound to the DataGrid.
For a final bit of fun I have this line:
searching_txt.text = file.nativePath;
This displays the path of each File being examined into a text field, the resulting effect is reministent of an anitvirus program searching for infected files!
+