<cffile> is CFML's core tag for file operations: reading a file's contents, writing or appending text to one, and (covered in the next lesson) handling an uploaded file. Modern CFScript code more often reaches for the equivalent built-in functions, fileRead(), fileWrite(), and fileAppend(), which do the same job without the tag syntax.
Learning Objectives
After completing this lesson, you'll be able to:
- Read, write, and append to a text file using both cffile and its CFScript function equivalents.
- Read a large file efficiently, line by line, instead of loading it entirely into memory.
- Know the real security gotcha with cffile: it performs no validation on its own.
How cffile Fits In
Your Code
cffile / fileRead / fileWrite
File on Disk
Every action, read, write, or append, is really the same round trip: your code asks cffile (or its CFScript function equivalent) to talk to a real file sitting on disk, and gets the result (or confirmation) back.
Reading a File
<cffile action="read" file="#expandPath('./message.txt')#" variable="message">
<cfoutput>#message#</cfoutput>message = fileRead(expandPath("./message.txt"));
writeOutput(message);Writing a File
<cffile action="write" file="#expandPath('./log.txt')#" output="Created by: #form.name#">fileWrite(expandPath("./log.txt"), "Created by: " & form.name);action="write" (and fileWrite()) overwrites the file completely if it already exists. For adding to an existing file without erasing it, use append instead.
Appending to a File
<cffile action="append" file="#expandPath('./log.txt')#" output="Appended by: #form.name#">fileAppend(expandPath("./log.txt"), "Appended by: " & form.name);The cffile Action Attribute: Full Reference
| action | What it does |
|---|---|
| read | Reads a text file's full contents into a variable |
| readbinary | Reads a binary file's contents (images, PDFs) into a variable |
| write | Creates a file, overwriting it if it already exists |
| append | Adds content to the end of an existing file |
| upload | Processes an uploaded file from a form submission (next lesson) |
| copy | Copies a file to a new location |
| move / rename | Moves or renames a file |
| delete | Deletes a file |
| info (Lucee only) | Retrieves file metadata, size, dates, without reading its contents |
| touch (Lucee only) | Creates an empty file, or updates an existing file's timestamp |
info and touch aren't part of Adobe ColdFusion's cffile at all, they're Lucee-specific additions. Confirm both engines support whatever action is actually needed before relying on either.
Lucee-Specific Extensions Worth Knowing
| Attribute | What it adds |
|---|---|
| cachedWithin | Caches a read/readbinary result (a timespan, or "request" scope), avoiding re-reading the same file repeatedly |
| allowedExtensions / blockedExtensions | Restricts which file extensions an upload can accept or must reject, built directly into the tag (Lucee 5.3.8.107+) |
| createPath | Automatically creates the destination directory for write, append, or touch if it doesn't already exist |
allowedExtensions and blockedExtensions matter specifically for the earlier security gotcha, on Lucee, they're a real, built-in way to restrict what cffile will accept, not something the developer has to reimplement entirely from scratch. Adobe ColdFusion instead relies on the accept and strict attributes on the upload action specifically, covered in the next lesson.
Reading a Large File Efficiently
fileRead() loads the entire file into memory at once, fine for a small config or log file, but wasteful for a genuinely large file. fileOpen() combined with fileReadLine() processes a file one line at a time instead.
fileOpen()
fileReadLine()
one line at a time
fileIsEOF()?
loop until true
fileClose()
fileObj = fileOpen(expandPath("./large-log.txt"), "read");
while (!fileIsEOF(fileObj)) {
line = fileReadLine(fileObj);
// process this one line
}
fileClose(fileObj);fileIsEOF() checks whether the end of the file has been reached, and the loop keeps going until it has. Always close the file with fileClose() when done, an open file handle left dangling can lock the file or leak resources.
A Real Gotcha: cffile Performs No Validation on Its Own
That's Adobe's own documentation, stated plainly. cffile does exactly what it's told, writing to whatever path it's given, reading whatever file exists there. Nothing about the tag itself stops a path built from unvalidated user input from writing somewhere it shouldn't, or reading a file it has no business exposing.
This example performs no error checking and does not incorporate any security measures. Before deploying an application that performs file uploads, ensure that you incorporate both error handling and security.
Common Beginner Mistakes
Using action="write" when the intent was to add to an existing file
write overwrites the file completely. Use append to add content without erasing what's already there.
Building a file path directly from user input with no validation
cffile performs no security checks on its own, per Adobe's own documentation. A path built from unvalidated input can read or write files far outside where the application intended.
Loading a genuinely large file with fileRead() instead of reading it line by line
fileRead() pulls the entire file into memory at once. For a large file, fileOpen() with fileReadLine() in a loop processes it incrementally instead.
Forgetting to close a file opened with fileOpen()
An open file handle left open with fileClose() never called can lock the file for other processes or leak resources over time.
Best Practices
- Validate and constrain any user-influenced path before passing it to cffile, never trust it directly.
- Use fileWrite/fileRead (or their tag equivalents) for small files, and fileOpen with fileReadLine for large ones.
- Always pair fileOpen() with a matching fileClose(), ideally inside a try/finally so it closes even if an error occurs mid-read.
- Prefer the CFScript functions (fileRead, fileWrite, fileAppend, fileOpen) in new CFScript-based code; the cffile tag remains fully supported but reads more naturally in Tag Syntax files.
Interview Questions
What's the difference between cffile action="write" and action="append"?
write creates the file, overwriting it entirely if it already exists. append adds content to the end of an existing file without erasing what's already there.
What's the CFScript equivalent of <cffile action="read">?
fileRead(path), which returns the file's contents directly as a string.
Why would you use fileOpen() and fileReadLine() instead of fileRead()?
fileRead() loads the entire file into memory in one call, which doesn't scale well for a genuinely large file. fileOpen() with fileReadLine() in a loop processes the file one line at a time instead.
Does cffile validate or restrict what paths it can read from or write to?
No. Adobe's own documentation states cffile performs no error checking or security measures on its own, validating any user-influenced path is the application's responsibility.
Name a cffile action that exists on Lucee but not on Adobe ColdFusion.
info (retrieves file metadata without reading its contents) and touch (creates an empty file or updates its timestamp) are both Lucee-specific, neither is part of Adobe ColdFusion's cffile.
Summary
In this lesson, you read, wrote, and appended to files using both cffile and its CFScript function equivalents (fileRead, fileWrite, fileAppend), read a large file efficiently line by line with fileOpen/fileReadLine/fileIsEOF, and covered the real gotcha that cffile performs no validation on its own.
What's Next?
The next lesson covers uploading files specifically, cffile's upload action, handling a form submission's file field, and the real security considerations around accepting a file from a user.