Sunday, July 19, 2009

Experiment with building your own CFDirectory List in Java - Part 1

While cfdirectory is a good tag, sometimes you just need just a bit more functionality in the filtering department. A recent question on stackoverflow asked whether it was possible to extend cfdirectory's filtering capabilities to perform an exclusive search (ie find all files that do not end with .cfm). The general consensus was no, and that the simplest work-around is to wrap the cfdirectory call in a function and use a QoQ to get the desired results. However, a poster named Nick piqued my curiosity with his comment about using java file filters. While he agreed it was not the simplest option, it got me to thinking: if you were to try and build your own cfdirectory list function in java, how might you do it?


Aren't there tools that do this already?
Let me say up front, I explored this idea as a learning exercise. I am sure I am not the first person to do this and obviously the simpler solution is to use a few QoQ's to obtain the desired results. But in this case I was more interested in the journey than finding the quickest route to the destination. Along the way I discovered there are several different ways to search a directory with java. But I eventually settled on using file filters, as it seemed the most common method.

Background on file filters
If you have done any work with java from ColdFusion, you have undoubtedly used the java.io.File class. For those that have not, it is a simple class used to represent a path on the file system (and despite the confusing name it can be used for both files and directories). What you may not know is the File class has several methods for retrieving information about the contents of a directory. The simplest is the listFiles() method. It returns an array of other File objects that represent any files or subfolders within a directory. You can easily iterate through that array to display the contents.


<cfscript>
dir = createObject("java", "java.io.File").init("c:/myFiles");
contents = dir.listFiles();
// Display the path of each item within the directory
if (IsDefined("contents"))
{
for (i = 1; i < arrayLen(contents); i++)
{
WriteOutput(contents[i].getPath() &"<br />");
}
}
</cfscript>


Now let us say you wanted to list only the .doc files within a directory. This is where file filters enter the picture. You could create your own custom file filter that determined if a file matched a particular file extension. Then pass that filter into one of the listFiles() methods. The listFiles() method would then use the filter to restrict the results, returning only .doc files in the array.

How do you create a file filter?
There are different types of filters, but in this case you would probably use a FilenameFilter. The FilenameFilter class is actually a very simple interface. To design your own filter, simply create a new class that implements java.io.FilenameFilter. Then implement the mandatory accept(File dir, String name) method. Inside that method is where you would place the logic that checks file extensions. The only requirement of the accept() method is that it return true if a given file matches your criteria. That is about all there is to it. As you can see in the code below, creating your own filter is not that complicated.

Custom Filter

import java.io.File;
import java.io.File;
import java.io.FilenameFilter;

public class FileExtensionFilter implements FilenameFilter{
private String fileExt;
public FileExtensionFilter(String fileExt) {
this.fileExt = fileExt.toLowerCase();
}

public boolean accept(File dir, String name) {
if (name.toLowerCase().endsWith(this.fileExt)) {
return true;
}
return false;
}
}


Using the Filter

Note: The custom class FileExtensionFilter must be added to the CF classpath first. For example, place the compiled class file in C:\ColdFusion8\wwwroot\WEB-INF\classes\

<cfscript>
// Retrieve only .DOC files
dir = createObject("java", "java.io.File").init("c:/myFiles");
// Create the filter
filter = createObject("java", "FileExtensionFilter").init(".doc");
contents = dir.listFiles();
if (IsDefined("contents"))
{
for (i = 1; i < arrayLen(contents); i++)
{
WriteOutput(contents[i].getPath() &"<br/>");
}
}
</cfscript>


Now the only other major piece needed to truly mimic cfdirectory is a bit of recursion. So you can search subdirectories. The basic algorithm in java is the same as it would be in ColdFusion. Just loop through the contents of a directory and check each item. If the item is a directory, repeat the process. Since the algorithm is so similar, I will not go into it here.

Continued in Part 2

0 comments:

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep