Create A Unique Filename When Moving With CFFile

Author: Steven Neiland
Published:

Warning: This blog entry was written two or more years ago. Therefore, it may contain broken links, out-dated or misleading content, or information that is just plain wrong. Please read on with caution.

It would seem obvious that the move action for cffile should give you the option to create a unique filename if the destination directory already contains a file with the same name. It would seem. Yet ColdFusion does not.

So here is a function I put together for a project a while back to do this for me.

<cffunction name="moveFile" access="private" output="false" returntype="string" 
      hint="Moves a file to a final location while preventing name conflicts. Returns the unique filename">

                              
      <cfargument name="sourceFilePath" required="true" type="string" hint="Path to the existing file">
      <cfargument name="destinationDirectory" required="true" type="string" hint="Path to the destination directory">
      
      <!--- Extract the filename from the source path --->
      <cfset var filename = getFileFromPath(arguments.sourceFilePath)>
      <cfset var counter = 1>
      <cfset var uniqueFileName = "">
      <cfset var destinationFilePath = "">

      <!--- Create an exclusive lock specific to the target directory --->      
      <cflock type="exclusive" timeout="30" name="#destinationDirectory#">

            <!--- If a file with the same name already exists at the destination --->
            <cfif fileExists(destinationDirectory & "/" & filename)>

                  <!--- Loop up to 100 times to try create a unique filename --->
                  <cfloop condition="counter LT 100">
                        <cfset destinationFilePath = destinationDirectory & "/" & counter & "_" & filename>
                  
                        <cfif fileExists(destinationFilePath)>
                              <cfset counter++>
                        <cfelse>
                              <cfset uniqueFileName = counter & "_" & filename>
                              <cfbreak/>
                        </cfif>
                  </cfloop>

            <!--- Filename does not already exist at the destination --->
            <cfelse>
                  <cfset uniqueFileName = filename>
                  <cfset destinationFilePath = folder & "/" & filename>
            </cfif>

            <!--- Provided the filename is not already in use at the destination or a unique filename was generated we can perform the move --->
            <cfif len(trim(uniqueFileName))>
                  <cffile action="move" source="#sourceFilePath#" destination="#destinationFilePath#">
            <cfelse>
                  <cfthrow message="Unable to move the file and create a unique filename at the destination">
            </cfif>
      </cflock>
            
      <cfreturn uniqueFileName>
</cffunction>

Note: While not strictly necessary the cflock is an added guarantee that this code does not encounter a race condition when moving files into a specific directory.

Reader Comments

Keith's Gravatar
Keith
Wednesday, March 25, 2015 at 11:32:25 AM Coordinated Universal Time

Thanks for this! I modified your code slightly to copy a file and to add the incremented number/underscore to the end of the filename (eg "myfile_1.pdf"). The code posted has an error with the "folder" variable not being defined - I changed this variable to "destinationDirectory".

Very nice work!

  • Please keep comments on-topic.
  • Please do not post unrelated questions or large chunks of code.
  • Please do not engage in flaming/abusive behaviour.
  • Comments that contain advertisments or appear to be created for the purpose of link building, will not be published.

Archives Blog Listing