How do I compress or zip a directory recursively?

In this example you are going to learn how to zip or compress a directory recursively. The zip file format allows us to compress multiple files. We use the java.util.zip.ZipOutputStream to compress the file. Each entry in the zip file is represented by the java.util.zip.ZipEntry class.

To compress a directory we must first get all the list of files in the specified directory and including all files in the subdirectory. In the example this task is handled by the getFileList() method. This method store the file list in the fileList variable to be use later during the compression process to create the ZipEntry.

Below is the code example showing you how to compress multiple files using zip.

package org.kodejava.util.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipDirectoryExample {
    private final List<String> fileList = new ArrayList<>();

    public static void main(String[] args) {
        String dir = "D:/Data";
        String zipFile = "D:/Data.zip";

        ZipDirectoryExample zip = new ZipDirectoryExample();
        zip.compressDirectory(dir, zipFile);
    }

    private void compressDirectory(String dir, String zipFile) {
        File directory = new File(dir);
        getFileList(directory);

        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            for (String filePath : fileList) {
                System.out.println("Compressing: " + filePath);

                // Creates a zip entry.
                String name = filePath.substring(directory.getAbsolutePath().length() + 1);

                ZipEntry zipEntry = new ZipEntry(name);
                zos.putNextEntry(zipEntry);

                // Read file content and write to zip output stream.
                try (FileInputStream fis = new FileInputStream(filePath)) {
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fis.read(buffer)) > 0) {
                        zos.write(buffer, 0, length);
                    }

                    // Close the zip entry.
                    zos.closeEntry();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Get files list from the directory recursive to the subdirectory.
     */
    private void getFileList(File directory) {
        File[] files = directory.listFiles();
        if (files != null && files.length > 0) {
            for (File file : files) {
                if (file.isFile()) {
                    fileList.add(file.getAbsolutePath());
                } else {
                    getFileList(file);
                }
            }
        }

    }
}

The code snippet above will compress the D:\Data directory, and it will produce a zip file called Data.zip. When running the program you can see something like this in the console:

Compressing: D:\Data\Aa.txt
Compressing: D:\Data\AA1a1.txt
Compressing: D:\Data\Bb.txt
Compressing: D:\Data\Cc.txt
Compressing: D:\Data\CC1c1.txt
Compressing: D:\Data\Dd.txt

How do I decompress a GZip file in Java?

In the previous example we have learn how to compress a file in GZIP format. To get the file back to its original version we will now learn how to decompress the gzip file. Just like the previous example, we are also going to use the FileInputStream and FileOutputStream class to read the compressed source file and to write out the decompressed file. While GZipOutputStream was used to create the gzip file, the GZipInputStream is the class that handles the decompression.

Here is your code snippet:

package org.kodejava.util.zip;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;

public class GZipDecompressExample {
    public static void main(String[] args) {
        // GZip input and output file.
        String sourceFile = "output.gz";
        String targetFile = "data-1.txt";

        try (
                // Create a file input stream to read the source file.
                FileInputStream fis = new FileInputStream(sourceFile);

                // Create a gzip input stream to decompress the source
                // file defined by the file input stream.
                GZIPInputStream gzis = new GZIPInputStream(fis);

                // Create file output stream where the decompression result
                // will be stored.
                FileOutputStream fos = new FileOutputStream(targetFile)) {

            // Create a buffer and temporary variable used during the
            // file decompress process.
            byte[] buffer = new byte[1024];
            int length;

            // Read from the compressed source file and write the
            // decompress file.
            while ((length = gzis.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

How do I compress a file in Gzip format?

In this code example we will learn how to compress a file using the gzip compression. By its nature, gzip can only compress a single file, you can not use it for compressing a directory and all the files in that directory.

Classes that you will be using to compress a file in gzip format includes the GZipOutputStream, FileInputStream and FileOutputStream classes. The steps for compressing a file described in the comments of the code snippet below.

package org.kodejava.util.zip;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

public class GZipCompressExample {
    public static void main(String[] args) {
        // GZip input and output file.
        String sourceFile = "data.txt";
        String targetFile = "output.gz";

        try (
                // Create a file input stream of the file that is going to be
                // compressed.
                FileInputStream fis = new FileInputStream(sourceFile);

                // Create a file output stream then write the gzip result into
                // a specified file name.
                FileOutputStream fos = new FileOutputStream(targetFile);

                // Create a gzip output stream object with file output stream
                // as the argument.
                GZIPOutputStream gzos = new GZIPOutputStream(fos)) {

            // Define buffer and temporary variable for iterating the file
            // input stream.
            byte[] buffer = new byte[1024];
            int length;

            // Read all the content of the file input stream and write it
            // to the gzip output stream object.
            while ((length = fis.read(buffer)) > 0) {
                gzos.write(buffer, 0, length);
            }

            // Finish file compressing and close all streams.
            gzos.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

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

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>

Maven Central

How do I read a zip file checksum value?

package org.kodejava.util.zip;

import java.io.*;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.CheckedInputStream;
import java.util.zip.Adler32;

public class UnzipWithChecksum {
    public static void main(String[] args) throws Exception {
        String zipName = "data-1.zip";

        try (FileInputStream fis = new FileInputStream(zipName);
             // Creating input stream that also maintains the checksum of 
             // the data which later can be used to validate data 
             // integrity.
             CheckedInputStream checksum =
                     new CheckedInputStream(fis, new Adler32());
             ZipInputStream zis =
                     new ZipInputStream(new BufferedInputStream(checksum))) {

            ZipEntry entry;

            // Read each entry from the ZipInputStream until no more entry
            // found indicated by a null return value of the getNextEntry()
            // method.
            while ((entry = zis.getNextEntry()) != null) {
                System.out.println("Unzipping: " + entry.getName());

                int size;
                byte[] buffer = new byte[1048];

                try (FileOutputStream fos =
                             new FileOutputStream(entry.getName());
                     BufferedOutputStream bos =
                             new BufferedOutputStream(fos, buffer.length)) {

                    while ((size = zis.read(buffer, 0, buffer.length)) != -1) {
                        bos.write(buffer, 0, size);
                    }
                    bos.flush();
                }
            }

            // Print out the checksum value
            long value = checksum.getChecksum().getValue();
            System.out.println("Checksum = " + value);
        }
    }
}