Unzip a file in CFMX with java.util.zip

The question of unzipping a file came up on the forums again. I’ve always replied that they can use CFX_Zip in CF5 and the java.util.zip package in CFMX. Never having had to actually use this myself in a ColdFusion application, I never relalized that java.util.zip is not all that straightforward.

After some research and one server crash, I put together this UDF.


function unzipFile(zipFilePath, outputPath) {

var zipFile = ""; // ZipFile
var entries = ""; // Enumeration of ZipEntry
var entry = ""; // ZipEntry
var fil = ""; //File
var filOutStream = "";
var bufOutStream = "";
var nm = "";
var pth = "";
var lenPth = "";

zipFile = createObject("java", "java.util.zip.ZipFile");
zipFile.init(zipFilePath);

entries = zipFile.entries();

while(entries.hasMoreElements()) {
entry = entries.nextElement();

if(NOT entry.isDirectory()) {
nm = entry.getName();

lenPth = len(nm) - len(getFileFromPath(nm));

if (lenPth) {
pth = outputPath & left(nm, lenPth);
} else {
pth = outputPath;
}

if (NOT directoryExists(pth)) {
fil = createObject("java", "java.io.File");
fil.init(pth);
fil.mkdirs();
}

filOutStream = createObject(
"java",
"java.io.FileOutputStream");

filOutStream.init(outputPath & nm);

bufOutStream = createObject(
"java",
"java.io.BufferedOutputStream");

bufOutStream.init(filOutStream);

copyInputStream(
zipFile.getInputStream(entry),
bufOutStream);
}
}

zipFile.close();
}

function copyInputStream(inStream, outStream) {

var buffer = repeatString(" ",1024).getBytes();
var l = inStream.read(buffer);

while(l GTE 0) {
outStream.write(buffer, 0, l);
l = inStream.read(buffer);
}
inStream.close();
outStream.close();
}

It accepts the full path of the zip file to unzip and the target path to extract to. The target path must end in a ” or ‘/’.

Credit really goes to Daniel Savarese since all I really did was convert his Java routine to ColdFusion. You can read his original article at http://www.devx.com.

So how did I crash my server creating this little UDF? When I converted Daniel’s while() clause with the inline variable assignment to CF, I removed the inline assignment and forgot to add it to the end of the while block. On the first iteration through the loop it never advanced the input stream and just kept writing the same data over and over to the same file. After the file got to about 3gb my server seemed sluggish and I noticed it wouldn’t respond. Luckily it was just my local instance and not even my dev server.

Important Note I didn’t realize it when I posted this originally, but the above code does not work in ColdFusion MX Updater 3. It does work in ColdFusion MX RedSky which will be available shortly.

This entry was posted in Uncategorized by Sam. Bookmark the permalink.

21 thoughts on “Unzip a file in CFMX with java.util.zip

  1. i tried to run your script, but i allways get this error:

    ‘Class coldfusion.runtime.StructBean can not access a member of class java.util.zip.ZipFile$2 with modifiers “public”‘

    im running coldfusion mx with updater3 on windows 2000. JVM 1.4.2 any ideas?

  2. Works for me on WinXP Pro / CFMX Updater3 + — Sam, please send this to CFLib.org, they have a zipFileNew() function there, this would be nice right beside it.

  3. Sebastian, thanks for pointing that out. My bad for not testing it in CFMXU3 before posting. I added a note at the end of the entry which had to be approved by Macromedia.

  4. Hm, is there a way to run it with CFMXU3?
    I had no time to test it, but we can call the class(from devx.com) directly, right?

  5. I’m not using the class from devx.com at all–I just converted it completely to CFScript. You can compile that class and use it from ColdFusion which is basicaly a Java wrapper for the built in java.util.zip classes. Most will find the UDF easier to use since it doesn’t require adding a new Java class to your classpath.

    You may also be able to modify the UDF to use a ZipInputStream instead of zipFile.entries(). There’s no reason this would work better than zipFile, but it just might not hit the particular bug that zipFile.entries() does.

    My suggestion is to wait untill RedSky is out and upgrade as soon as it is.

  6. RedSky(CFMX 6.1) is out and I´ve finished some tests. Your code only works with RedSky(CFMX 6.1), and only if you install the “new version of ColdFusion MX”, which means on top of JRun4 as a J2EE-server. If you just update your ColdFusion MX to 6.1 it still doesn´t work.

    Nice UDF with some limitations. ;-)

  7. Sebastian, the code works for me in versions of RedSky that are updated from CFMX. I’m not running the JRun/CFMX version at all (did once during the beta, but not now). The unzip code works on RedSky standalone which is what I use on my laptop and work desktop, RedSky with IIS on my dev pc, and RedSky J2EE on BEA WebLogic on my dev pc.

    I’ll post a separate entry on the error message, now that I can fully talk about it.

  8. The script doesn’t seem to work for .gz files ?? am i missing something the documentation on the java object references gzip.

  9. Andrew,

    gzip is a slightly different format from zip so this routine will not work with gzip. I have another routine that should work but I never posted it ’cause I never had enough testing done. I’ll e-mail to you and hopefully you can help with testing.

    Thanks,

    Sam

  10. I’d be interested in getting the version to decompress a *.gz file. I’ll even report back with my testing info. Thanks, btw nice work.

  11. Hi,
    because the upload of thousands of small files to my webspace takes so long I would like to zip it before the upload and unzip it via coldfusion.
    Could anybody recommend a viable solution for me?

    Kind regards
    Thorsten

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>