CFZip, CFZipParam, And Virtual File System (RAM) Directories

Posted December 9, 2009 at 9:22 AM by Ben Nadel

Tags: ColdFusion

NOTE: I was not running the latest version of ColdFusion 9. Using the freshest install, this now works. My bad :)

As part of my "Best of ColdFusion 9" entry, I needed a way to download IMAP-based mail attachments. To show off some of the features of ColdFusion 9, I figured I would have CFIMAP save the attachments to the virtual file system (RAM disk - ram://) and them ZIP them up and return the resultant archive to the client. I had a heck of a time getting that to work; eventually, I narrowed it down to what I think is a bug in the interaction between the CFZip tag and the RAM disk - specifically, when it comes to zipping an entire source directory off the RAM disk.

To demonstrate this (and get some feedback as to whether or not this is a bug), I went about creating a ZIP file both from the physical file system and from CF9's virtual file system. As my control case, I created the ZIP archive based on an entire physical directory first:

  • <!---
  • Create a ZIP file of the Files directory located on the
  • physical file system.
  • --->
  • <cfzip
  • action="zip"
  • source="#expandPath( './files/' )#"
  • file="#expandPath( './physical_source.zip' )#"
  • overwrite="true"
  • />
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './physical_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Physical File System
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './physical_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

This code is pretty straightforward; I set the source of the CFZip tag to be the entire "./files/" directory. Then, to make sure everything worked as expected, I read each binary image from the zip archive and wrote it to the browser as a visual confirmation of the successful life cycle. When we run the above code, we get the following page output:

 
 
 
 
 
 
CFZip, CFZipParam, And The Virtual File System - Physical File System Control Case. 
 
 
 

As you can see, our control case works like a charm.

Next, I tried to do the same thing using a directory on the virtual file system (RAM disk) as the source directory. The code is basically the same, except for that I had to copy the files to the virtual file system before zipping them:

  • <!---
  • Delete RAM directory in case it exists (I needed this to run
  • the page more than once).
  • --->
  •  
  • <cfdirectory
  • action="delete"
  • directory="ram://cfzip-files/"
  • recurse="true"
  • />
  •  
  •  
  • <!---
  • Create the directory in our RAM disk (we will need to copy
  • the physical files to this RAM directory before we can ZIP
  • them).
  • --->
  • <cfdirectory
  • action="create"
  • directory="ram://cfzip-files/"
  • />
  •  
  • <!--- Copy the physical files to the ram disk. --->
  • <cfloop
  • index="fileName"
  • list="girl1.jpg,girl2.jpg,girl3.jpg"
  • delimiters=",">
  •  
  • <cfset fileCopy(
  • expandPath( "./files/#fileName#" ),
  • "ram://cfzip-files/#fileName#"
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Create a ZIP file of the cfzip-files directory located on
  • the virtual file system.
  • --->
  • <cfzip
  • action="zip"
  • source="ram://cfzip-files/"
  • file="#expandPath( './virtual_source.zip' )#"
  • overwrite="true"
  • />
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './virtual_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Virtual File System
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './virtual_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

As you can see, if you ignore the file-copy at the top, this code is basically the same as the physical file system control case. However, when we run this code, we get the following page output:

.... nothing ....

Absolutely nothing gets output to the screen. Not even a ColdFusion error. However, when I check my Application log in the ColdFusion administrator, I see the following exception:

'' The specific sequence of files included or processed is: C:\ColdFusion9\wwwroot\testing\cfzip\vfs.cfm

That's doesn't really help me at all in terms of useful exception messages. After a bit of trial and error, I found that I could finally create the zip archive if I added some CFZipParam tags to the CFZip parent tag. I could keep the virtual directory as the source of the archive, but the CFZipParam tags had to specify the files that would get included:

  • <!---
  • Delete RAM directory in case it exists (I needed this to run
  • the page more than once).
  • --->
  •  
  • <cfdirectory
  • action="delete"
  • directory="ram://cfzip-files/"
  • recurse="true"
  • />
  •  
  •  
  • <!---
  • Create the directory in our RAM disk (we will need to copy
  • the physical files to this RAM directory before we can ZIP
  • them).
  • --->
  • <cfdirectory
  • action="create"
  • directory="ram://cfzip-files/"
  • />
  •  
  • <!--- Copy the physical files to the ram disk. --->
  • <cfloop
  • index="fileName"
  • list="girl1.jpg,girl2.jpg,girl3.jpg"
  • delimiters=",">
  •  
  • <cfset fileCopy(
  • expandPath( "./files/#fileName#" ),
  • "ram://cfzip-files/#fileName#"
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Create a ZIP file of the cfzip-files directory located on
  • the virtual file system.
  •  
  • NOTE: Because the CFZip tag does not seem to play well with
  • virtual directories as the source, we need to define the
  • individual files using CFZipParam tags.
  • --->
  • <cfzip
  • action="zip"
  • source="ram://cfzip-files/"
  • file="#expandPath( './virtual_source.zip' )#"
  • overwrite="true">
  •  
  • <cfzipparam source="girl1.jpg" />
  • <cfzipparam source="girl2.jpg" />
  • <cfzipparam source="girl3.jpg" />
  •  
  • </cfzip>
  •  
  •  
  • <!---
  • Read the images from the zip file and output them to the
  • screen (to make sure the full cycle works).
  • --->
  • <cfzip
  • name="fileList"
  • action="list"
  • file="#expandPath( './virtual_source.zip' )#"
  • />
  •  
  •  
  • <h1>
  • CFZip - Virtual File System (+CFZipParam)
  • </h1>
  •  
  • <!--- Loop over the zipped files to extract and output. --->
  • <cfloop query="fileList">
  •  
  • <!--- Read the image binary from the zip. --->
  • <cfzip
  • variable="imageBinary"
  • action="readbinary"
  • file="#expandPath( './virtual_source.zip' )#"
  • entrypath="#fileList.directory##fileList.name#"
  • />
  •  
  • <!--- Write the image to the client. --->
  • <cfimage
  • action="writetobrowser"
  • source="#imageBinary#"
  • height="200"
  • style="float: left ; margin-right: 10px ;"
  • />
  •  
  • </cfloop>

Notice that this is exactly the same as the previous code, except for the addition of three CFZipParam tags. This time, when we run the above code, we get the following page output:

 
 
 
 
 
 
CFZip, CFZipParam, And The Virtual File System - Virtual File System Case. 
 
 
 

Now, the CFZip tag works as expected and interacts properly with the virtual file system.

Is this a bug? It certainly feels like one to me. I have looked around the documentation and I don't see any restrictions on directory-level actions.




Reader Comments

Dec 9, 2009 at 9:46 AM // reply »
11,314 Comments

It looks like this is the same bug:

http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=79101


Dec 9, 2009 at 10:37 AM // reply »
11,314 Comments

Ooops, as it turns out, I was NOT running the latest version of ColdFusion 9.

After upgrading my install, this now works.


Dec 9, 2009 at 11:57 AM // reply »
14 Comments

Hey Ben.

Your CF9 was out of date? What version are you running, and where did you find a hotfix? I did not see any updates at all for CF9 on the adobe update support site.

Cheers dude.

-Brian


Dec 9, 2009 at 11:59 AM // reply »
11,314 Comments

@Brian,

I didn't hotfix. I just uninstalled and re-installed. I may have still been running a pre-release version.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 20, 2013 at 3:15 AM
A Billion Wicked Thoughts By Ogi Ogas And Sai Gaddam
nice post i love it thanks 4 u :) ... read »
seb
Jun 20, 2013 at 2:32 AM
Working With Inherited Collections In AngularJS
@mike, @ben, The best article about scope and prototypal prototypical inheritance in angularjs is http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical- ... read »
Jun 20, 2013 at 2:17 AM
ColdFusion NumberFormat() Exploration
Nice read thanks Ben, Is there a way to mask a negative number? Long story short in the finance sector when you go 'short' on a stock you want the price to fall this is a good thing because you are ... read »
Jun 20, 2013 at 1:09 AM
The Beauty Of The jQuery Each() Method
my html code : <html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="nss.js"> ... read »
Jun 19, 2013 at 11:31 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Ben, bunch to learn indeed, but thats fun part : ) ... read »
Jun 19, 2013 at 10:41 PM
Referencing ColdFusion Query Columns In A Loop Using Both Array And Dot Notation
Burdock-roots Are you going fat day by day? You need to be good for your family and make some money too. So we bring for you a best product that helps you to be more energetic every day. You will b ... read »
Jun 19, 2013 at 9:52 PM
Working With Inherited Collections In AngularJS
I recognize the applicability of your solution, and how easy it makes to share data across multiple views or even "submodules" of rather simple application. But it seems to me that it creat ... read »
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools