Pages

Sunday, 15 July 2012

Generating Zip Files From Multiple Files In Grails

This article describes how to write a controller in Grails that takes a number of files on the server and bundles them in to a zip file. The resulting file is put on to the response so the application user can download it.

There are already a number of articles out there on creating zip files in groovy. This (short!) article pulls them together and includes how to handle multiple, fairly sizeable files and how to set the response headers correctly.

The Code

ByteArrayOutputStream baos = new ByteArrayOutputStream()
ZipOutputStream zipFile = new ZipOutputStream(baos)

  album.tracks.each {track ->
    if (track.mp3DownloadPath != "") {
      File file = new File(grailsApplication.config.tracks.root.directory+track.mp3DownloadPath)
      zipFile.putNextEntry(new ZipEntry(track.title+".mp3"))
      file.withInputStream { i ->
       
        zipFile << i

      }
      zipFile.closeEntry()
     }
    }
    zipFile.finish()
    response.setHeader("Content-disposition", "filename=\"${album.title}.zip\"")
    response.contentType = "application/zip"
    response.outputStream << baos.toByteArray()
    response.outputStream.flush()

Points to Note

  • We use the GDK withInputStream method on File to create a new InputStream. This automatically close the InputStream for us after the closure is exited.
  • The Groovy left-shit operator <<, is a good short-hand for copying an InputStream into an OutputStream. You can use it to copy byte arrays into OutputStreams too.
  • zipFile.finish() is called after all the files have been added to the ZipOutputStream. Not calling this resulted in a corrupted zip file.
  • When setting the response header, it was necessary to wrap the file name in double quotes to prevent Chrome occassionally complaining about a 'Duplicate Headers Received from Server' error.  response.setHeader("Content-disposition", "filename=\"${album.title}.zip\"")

4 comments:

  1. Excellent tutorial. Worked like a charm.

    ReplyDelete
  2. Great tutorial...thx david
    is it possible to download multiple files directly without zip?

    ReplyDelete
  3. I am getting this Exception: org.codehaus.groovy.grails.web.pages.exceptions.GroovyPagesException: Error processing GroovyPageView: getOutputStream() has already been called for this response

    If anyone has idea that why I am getting this exception please guide me if I am doing anything wrong. Thanks,

    ReplyDelete