How do I create zip file in Servlet for download?

The example below is a servlet that shows you how to create a zip file and send the generated zip file for user to download. The compressing process is done by the zipFiles method of this class.

For a servlet to work you need to configure it in the web.xml file of your web application which can be found after the code snippet below.

package org.kodejava.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@WebServlet(urlPatterns = "/zipservlet")
public class ZipDownloadServlet extends HttpServlet {
    public static final String FILE_SEPARATOR = System.getProperty("file.separator");

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            // The path below is the root directory of data to be
            // compressed.
            String path = getServletContext().getRealPath("data");

            File directory = new File(path);
            String[] files = directory.list();

            // Checks to see if the directory contains some files.
            if (files != null && files.length > 0) {

                // Call the zipFiles method for creating a zip stream.
                byte[] zip = zipFiles(directory, files);

                // Sends the response back to the user / browser. The
                // content for zip file type is "application/zip". We
                // also set the content disposition as attachment for
                // the browser to show a dialog that will let user 
                // choose what action will he do to the content.
                ServletOutputStream sos = response.getOutputStream();
                response.setContentType("application/zip");
                response.setHeader("Content-Disposition", "attachment; filename=\"DATA.ZIP\"");

                sos.write(zip);
                sos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Compress the given directory with all its files.
     */
    private byte[] zipFiles(File directory, String[] files) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(baos)) {
            byte[] bytes = new byte[2048];

            for (String fileName : files) {
                String path = directory.getPath() +
                        ZipDownloadServlet.FILE_SEPARATOR + fileName;
                try (FileInputStream fis = new FileInputStream(path);
                     BufferedInputStream bis = new BufferedInputStream(fis)) {

                    zos.putNextEntry(new ZipEntry(fileName));

                    int bytesRead;
                    while ((bytesRead = bis.read(bytes)) != -1) {
                        zos.write(bytes, 0, bytesRead);
                    }
                    zos.closeEntry();
                }
            }

            zos.close();
            return baos.toByteArray();
        }
    }
}

Maven dependencies

<!--https://search.maven.org/remotecontent?filepath=javax/servlet/javax.servlet-api/4.0.1/javax.servlet-api-4.0.1.jar-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>

Maven Central

15 Comments

  1. Nice post, done exactly the same with my servlet.

    The files I need to ZIP are stored as BLOB and add them as byte[]. When I add them as a ZIPEntry everything works fine, but when I review the exported files, they don’t have a content type individually and marked as invalid content, any recommendations?

    Reply
  2. Hi there,

    I used your code, it works great!, well I haven’t tested it with real data but it seems to be working fine, one question, where is the “data” folder in your example?

    Thank you!

    Reply
    • Hi Miguel,

      In this case the data directory should be under you webapp root directory. For example if your web application root directory is webapp then the data should be webapp/data. I hope that helps you.

      Reply
  3. I tried running the code in jsp, then I can get a getOutputStream() has already been called for this response. any idea for this?

    Reply
  4. This solution won’t work for large files as there is a byte[] zip = zipFiles(directory, files); in it. The resulting file has to fit into memory. Prefer using directly the Servlet outputStream by wrapping it into the ZipOutputStream. ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()); That way, you will consume less memory.

    Reply

Leave a Reply to Riaz Ahmed Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.