A few days ago, I posted my ColdFusion ZipUtility.cfc code that I was developing in order to zip code snippet files. One of the short coming of that version of the ZipUtility.cfc was that it required writing the Zip data to a physical file on the server. This is highly recommending for anything that is going to be large, but for my use case (zipping together code snippets), the files sizes are going to be so minimal, I didn't want to bother writing the zip data to the file system.
To overcome this, I have updated the ColdFusion ZipUtility.cfc's Compress() method to take either a file name or an existing output stream. If a file is passed in, then it just creates the standard File Output Stream and wraps the Zip Output Stream around it. If, however, you pass in an output stream of some sort, the Zip Output Stream then wraps around that.
Here is an updated example that does not write any data to a file on the file system:
Launch code in new window » Download code as text file »
Notice that at the bottom, I am creating a Java ByteArrayOutputStream. I chose this output stream (from the numerous Java file I/O decorators) since it seemed like the easiest one from which to get a binary object (ToByteArray()) that I could then use with ColdFusion CFContent and the Variable attribute.
Once I create the output stream, I then just pass it into the ColdFusion ZipUtility.cfc's Compress() method. Since Java objects are passed by reference, I don't have to worry about getting any returned reference to the output object. After the zip is done being written to the output, I then convert it to a binary object (using the output stream's ToByteArray() method) and stream it to the client using the CFContent tag.
This way, all file output is avoided and there is nothing to clean up. Running the above code, here is the result zip file. I have openned up several of the items to prove that adding text entries and file binaries still works:
| | | | ||
| | ![]() | | ||
| | | |
The updated ColdFusion ZipUtility.cfc I am using to create these zip files is here:
Launch code in new window » Download code as text file »
Remember, this method is recommended ONLY for small files and small collections. If you do all this without writing to the file system, you are using up the server's RAM (where the output stream is built). If you try this with a huge file, it might take down the server. I know that my code snippets will always be comparatively small, and therefore, I am not worried about using up the RAM. For me, the ease of not having to create a file outweighs the RAM costs.
Download Code Snippet ZIP File
Comments (13) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
ColdFusion 8 Beta Released - ColdFusion 8 Release Date Contest Still Open
Inline Code Snippets Can Now Be Downloaded As One Zip File
And how much RAM does your code require now?
Posted by Warren on May 30, 2007 at 8:29 AM
@Warren,
The amount of RAM required is going to be directly related to the size of the data being compressed. If you are compressing a 100K file, you are going to need RAM to load the 100K file (less than 100K of RAM since it uses a file input stream which does not read it all at once... I think), plus the RAM to allocate space for the ZipUtility.cfc itself, plus RAM for the zip output stream (which would be no MORE than 100K assuming zero compression was possible).
Of course, I am not using this to zip 100K of stuff, so it will use much less RAM. But you get the idea - the more you zip, the more space is required in RAM to hold the individual files plus the output stream data.
If you zip a tiny file, it will take a tiny amount of RAM.
Posted by Ben Nadel on May 30, 2007 at 9:00 AM
I keep getting an object instaniation error withthe File Input Stream in the compression fucntion? I added the classpath to my cf admin. Any suggestions ?
Posted by alc on Jun 11, 2007 at 9:29 AM
You shouldn't need to add any class path. All the file IO stuff is already part of Java that ColdFusion is running on top of. Make sure your file path is fully expanded.
Posted by Ben Nadel on Jun 11, 2007 at 9:50 AM
this is awesome -- set me off noodling a number of modifications/uses for something similar I need to create.
thought maybe you could weigh in on an issue I'm trying to solve -- attempting to apply this in a way to also allow generation of two empty folders within this resulting .zip I've had little to no success in my reading up on the underlying java to accomplish. any directions you could point me in ?
Posted by Alex Polson on Jul 24, 2007 at 11:03 AM
@Alex,
It's interesting that you mention that, cause I just wrote my 4th part of a 5 part series on using the new CFZip tag in ColdFusion 8. I played around with trying to add empty directories to an archive using CF8 and I could not figure it out there either. It always told me that you couldn't create a zip with nothing in it.
I suppose what you could do is zip a file into a directory, then delete the file... this might keep the directory itself. I know that a zip CAN have empty directories cause I can create them using WinZip / WinRAR.
Long story short, I don't have an answer for you at this moment, but I can poke around, see what I can find.
Posted by Ben Nadel on Jul 24, 2007 at 11:07 AM
I am getting following error on last line of code i.e. <cfcontent type="application/x-zip-compressed" variable="#objOutputStream.ToByteArray()#"/>
Error :
Attribute validation error for tag CFCONTENT.
The tag does not allow the attribute(s) VARIABLE. The valid attribute(s) are DELETEFILE,FILE,RESET,TYPE.
Posted by @Lalit on Nov 14, 2007 at 1:00 PM
@Lalit,
The Variable attribute of the CFcontent tag was introduced in CFMX 7. I assume you are in MX6. In order to get it to work, you are going to have to actually write the Zip binary data to the underlying byte buffer of the response (which sits on top of the character response buffer).
At lunch, I will see if I can whip up an example of this.
Posted by Ben Nadel on Nov 14, 2007 at 1:07 PM
Yes, you are right, i am using CF6. If possible then Please give me some example.
Thanks for quick response.
Posted by @Lalit on Nov 14, 2007 at 1:16 PM
@Lalit,
I was gonna try to write up an example, but Christian Cantrell has a pretty good explanation here (which is basically what I would have copied):
http://weblogs.macromedia.com/cantrell/archives/2003/06/using_coldfusio.cfm
From the comments, it looks like there are few issues with MX 6.1, but some of the code just needs to be commented out. Hope this helps you out a bit. I am not too familiar with the underlying servlet stuff.
Posted by Ben Nadel on Nov 14, 2007 at 2:41 PM
Hello,
On CF6, and still having trouble with
<cfcontent type="application/x-zip-compressed" variable="#objOutputStream.ToByteArray()#"/>
Couldn't quite get the solution here to work: http://weblogs.macromedia.com/cantrell/archives/2003/06/using_coldfusio.cfm
Does anyone have other ideas/approaches?
Any help would be greatly appreciated.
Posted by sam davis on Nov 20, 2007 at 11:20 AM
I used this CFC since I have to zip some UTF-8 content. It doesn't work with UTF-8 content. With chines or arabic characters you will have wrong results. I started to go into the java classes to correct that but I remember the new CFZIP tag with CF8. I used the CF8 CFZIP tag with success. I hope that could help.
Posted by Eric00000007 on Aug 13, 2008 at 5:36 AM
@Eric00000007,
Yeah, now that ColdFusion 8 has built-in zip functionality with CFZip and CFZipParam, I would start using that. I am sure it is much more powerful than my hacked-together object.
Posted by Ben Nadel on Aug 13, 2008 at 8:09 AM