<cfdirectory> handles directory-level operations: listing what's inside a folder, creating a new one, deleting or renaming one. Like cffile, most current CFScript code reaches for the equivalent built-in functions instead, directoryList(), directoryCreate(), directoryDelete(), directoryRename(), and directoryExists().
Learning Objectives
After completing this lesson, you'll be able to:
- List a directory's contents and read the result's columns, with both cfdirectory and directoryList().
- Create, delete, and rename a directory.
- Filter a directory listing to only the files actually needed.
How cfdirectory Fits In
Your Code
cfdirectory / directoryList
Directory on Disk
Listing a Directory
<cfdirectory directory="#expandPath('./uploads')#" name="files" sort="size ASC, name DESC">
<cfoutput query="files">
#files.name# — #files.size# bytes — #files.type#<br>
</cfoutput>files = directoryList(expandPath("./uploads"), false, "query", "*", "size ASC, name DESC");
for (row in files) {
writeOutput(row.name & " — " & row.size & " bytes — " & row.type & "<br>");
}The Query Result Columns
| Column | Meaning |
|---|---|
| name | The file or directory's name |
| directory | The path containing this entry |
| size | Size in bytes |
| type | "File" or "Dir" |
| dateLastModified | When the entry was last modified |
| attributes | Windows-only file attributes |
| mode | Unix-only octal permissions |
attributes and mode are platform-specific, expect one or the other to be empty depending on the server's operating system, not both populated at once.
Creating, Deleting, and Renaming
<cfdirectory action="create" directory="#expandPath('./new-folder')#"><cfdirectory action="delete" directory="#expandPath('./old-folder')#">directoryCreate(expandPath("./new-folder"));
directoryDelete(expandPath("./old-folder"));
directoryRename(expandPath("./old-name"), expandPath("./new-name"));action="delete" (and directoryDelete()) fails on a non-empty directory unless told to recurse, deleting a directory that still has files inside requires explicitly opting into recursive deletion.
Filtering a Listing
All Entries
filter Pattern
e.g. *.cfm
Matching Files Only
<cfdirectory directory="#expandPath('./src')#" name="cfmFiles" filter="*.cfm|*.cfc">Multiple patterns are separated with a pipe (|). Filter pattern matching is case-sensitive on Unix and Linux, but not on Windows, worth remembering if a filter mysteriously matches fewer files after moving to a different server.
Lucee-Specific Extensions Worth Knowing
| Feature | What it adds |
|---|---|
| action="copy" | Copies an entire directory to a new location, not available in Adobe ColdFusion's cfdirectory |
| action="info" | Retrieves directory metadata directly, without listing its full contents |
| action="forcedelete" | Deletes a directory and everything inside it in one step, without a separate recurse flag |
| filter as a closure | Accepts a function that receives each name and returns true/false, instead of only a wildcard pattern string |
None of these four exist in Adobe ColdFusion's cfdirectory. Confirm which engine a project targets before relying on any of them.
Common Beginner Mistakes
Trying to delete a non-empty directory without recursing
action="delete" fails on a directory that still contains files unless recursion is explicitly enabled, it doesn't silently delete everything inside by default.
Assuming attributes and mode are both always populated
attributes is Windows-only and mode is Unix-only, expect whichever doesn't apply to the server's OS to come back empty.
Assuming a filter pattern's case sensitivity is the same across servers
Filter matching is case-sensitive on Unix/Linux but not on Windows, a filter that worked in local development can behave differently once deployed.
Using a Lucee-only action (copy, info, forcedelete) in code meant to also run on Adobe ColdFusion
None of those three actions exist on Adobe ColdFusion's cfdirectory at all, code relying on them won't run there without a rewrite.
Best Practices
- Use directoryExists() to check before creating or deleting, rather than relying purely on catching an error.
- Prefer a specific filter pattern over listing everything and filtering the result in CFML code afterward.
- Be explicit about recursion when deleting, an accidental non-recursive delete failing loudly is far better than an accidental recursive delete succeeding on the wrong folder.
Interview Questions
What does the type column distinguish in a cfdirectory listing?
Whether a given row is a file or a subdirectory ("File" or "Dir"), letting code branch differently for files versus nested folders in the same listing.
Why might attributes be empty on one server and mode be empty on another?
attributes reflects Windows-only file attributes, and mode reflects Unix-only octal permissions. Whichever doesn't apply to the server's actual operating system comes back empty.
What happens if you try to delete a directory that still has files inside it, without recursion?
The delete fails. Deleting a non-empty directory requires explicitly opting into recursive deletion, it isn't the default behavior.
Name a cfdirectory action available in Lucee but not in Adobe ColdFusion.
copy (copying an entire directory), info (retrieving metadata without a full listing), and forcedelete (deleting a directory and its contents in one step) are all Lucee-only.
Summary
In this lesson, you listed a directory's contents and read the result's columns, created, deleted, and renamed directories, filtered a listing with wildcard patterns, and covered real Lucee-only extensions (copy, info, forcedelete, and closure-based filtering) that Adobe ColdFusion's cfdirectory doesn't have.
What's Next?
The next lesson covers cfzip, compressing files into an archive and extracting them back out.