By dave | April 27, 2015

Following on from one of our popular articles on Reading a zip file from java using ZipInputStream  we’ve put together a new article on how to create a zip archive using Java. The below example uses ZipOutputStream to create a zip file from all the items in a directory.

Zip files are written slightly differently to a normal stream in that each entry is put into the stream one at a time. So the procedure is as follows:

  1. Create a zip archive using ZipOutputStream
  2. Create a new ZipEntry to represent the file to be added
  3. Write the bytes for the file
  4. Repeat steps 2,3 for each file to be added
  5. Close the archive

Zip File Writer Example

package com.thecoderscorner.example.compression;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * This class generates a zip archive containing all the
 * files within constant ZIP_DIR.
 * For this example you'll need to put a few files in the
 * directory ZIP_DIR, and it will generate a zip archive
 * containing all those files in the location OUTPUT_ZIP.
 * Minimum Java version: 8
 */
public class ZipWriter {
    private final static Logger LOG = Logger.getLogger("Zip");

    public final static String ZIP_DIR = "c:/Dev/temp/zipwrite";
    public static final String OUTPUT_ZIP = "c:/dev/temp/output.zip";


    /**
     * This method creates the zip archive and then goes through
     * each file in the chosen directory, adding each one to the
     * archive. Note the use of the try with resource to avoid
     * any finally blocks.
     */
    private void createZip(String dirName) {
        // the directory to be zipped
        Path directory = Paths.get(dirName);

        // the zip file name that we will create
        File zipFileName = Paths.get(OUTPUT_ZIP).toFile();

        // open the zip stream in a try resource block, no finally needed
        try( ZipOutputStream zipStream = new ZipOutputStream(
                        new FileOutputStream(zipFileName)) ) {

            // traverse every file in the selected directory and add them
            // to the zip file by calling addToZipFile(..)
            DirectoryStream<Path> dirStream = Files.newDirectoryStream(directory);
            dirStream.forEach(path -> addToZipFile(path, zipStream));

            LOG.info("Zip file created in " + directory.toFile().getPath());
        }
        catch(IOException|ZipParsingException e) {
            LOG.log(Level.SEVERE, "Error while zipping.", e);
        }
    }

    /**
     * Adds an extra file to the zip archive, copying in the created
     * date and a comment.
     * @param file file to be archived
     * @param zipStream archive to contain the file.
     */
    private void addToZipFile(Path file, ZipOutputStream zipStream) {
        String inputFileName = file.toFile().getPath();
        try (FileInputStream inputStream = new FileInputStream(inputFileName)) {

            // create a new ZipEntry, which is basically another file
            // within the archive. We omit the path from the filename
            ZipEntry entry = new ZipEntry(file.toFile().getName());
            entry.setCreationTime(FileTime.fromMillis(file.toFile().lastModified()));
            entry.setComment("Created by TheCodersCorner");
            zipStream.putNextEntry(entry);

            LOG.info("Generated new entry for: " + inputFileName);

            // Now we copy the existing file into the zip archive. To do
            // this we write into the zip stream, the call to putNextEntry
            // above prepared the stream, we now write the bytes for this
            // entry. For another source such as an in memory array, you'd
            // just change where you read the information from.
            byte[] readBuffer = new byte[2048];
            int amountRead;
            int written = 0;

            while ((amountRead = inputStream.read(readBuffer)) > 0) {
                zipStream.write(readBuffer, 0, amountRead);
                written += amountRead;
            }

            LOG.info("Stored " + written + " bytes to " + inputFileName);


        }
        catch(IOException e) {
            throw new ZipParsingException("Unable to process " + inputFileName, e);
        }
    }

    /**
     * Instantiate a new ZipWriter and provide the directory we want to compress.
     * @param args command line args not used
     */
    public static void main(String[] args) {
        ZipWriter zw = new ZipWriter();
        zw.createZip(ZIP_DIR);
    }

    /**
     * We want to let a checked exception escape from a lambda that does not
     * allow exceptions. The only way I can see of doing this is to wrap the
     * exception in a RuntimeException. This is a somewhat unfortunate side
     * effect of lambda's being based off of interfaces.
     */
    private class ZipParsingException extends RuntimeException {
        public ZipParsingException(String reason, Exception inner) {
            super(reason, inner);
        }
    }
}

When run you should see the following output


Apr 27, 2015 4:23:09 PM com.thecoderscorner.example.compression.ZipWriter addToZipFile
INFO: Generated new entry for: c:\Dev\temp\zipwrite\LICENSE.txt
Apr 27, 2015 4:23:09 PM com.thecoderscorner.example.compression.ZipWriter addToZipFile
INFO: Stored 566 bytes to c:\Dev\temp\zipwrite\LICENSE.txt
Apr 27, 2015 4:23:09 PM com.thecoderscorner.example.compression.ZipWriter addToZipFile
INFO: Generated new entry for: c:\Dev\temp\zipwrite\NOTICE.txt
Apr 27, 2015 4:23:09 PM com.thecoderscorner.example.compression.ZipWriter addToZipFile
INFO: Stored 661 bytes to c:\Dev\temp\zipwrite\NOTICE.txt
Apr 27, 2015 4:23:09 PM com.thecoderscorner.example.compression.ZipWriter createZip
INFO: Zip file created in c:\Dev\temp\zipwrite

Lastly, here is the zip file as reported by Cygwin unzip


$ unzip -t output.zip
Archive:  output.zip
    testing: LICENSE.txt              OK
    testing: NOTICE.txt               OK
No errors detected in compressed data of output.zip.

$ unzip -l output.zip
Archive:  output.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
      566  04-27-2015 16:23   LICENSE.txt
Created by TheCodersCorner
      661  04-27-2015 16:23   NOTICE.txt
Created by TheCodersCorner
---------                     -------
     1227                     2 files

Other pages within this category

comments powered by Disqus

This site uses cookies to analyse traffic, and to record consent. We also embed Twitter, Youtube and Disqus content on some pages, these companies have their own privacy policies.

Our privacy policy applies to all pages on our site

Should you need further guidance on how to proceed: External link for information about cookie management.

Send a message
X

Please use the forum for help with UI & libraries.

This message will be securely transmitted to our servers.