Packaging a zip file from Java using Apache Commons compress

Filed under: Java, Programming, — Tags: Gradle, org.apache.commons.compress, zip — Thomas Sundberg — 2015-08-21

How do you create a zip file with Java? One option is to use Apache Commons Compress.

This example shows you how.

I use Gradle to define dependencies needed as well as building the example.

The files needed are these:

example
|-- build.gradle
`-- src
    `-- test
        |-- java
        |   `-- se
        |       `-- thinkcode
        |           `-- zip
        |               `-- ZipFileTest.java
        `-- resources
            `-- readme.txt

Three different files.

Project file

Create a Gradle project file with this content:

build.gradle

apply plugin: "java"

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-compress:1.9'
    compile 'commons-io:commons-io:2.4'

    testCompile 'junit:junit:4.12'
}

This defines the dependencies I use. Most notably org.apache.commons:commons-compress:1.9 that will do the heavy lifting.

The implementation

The implementation is then done in a test class. I am a fan of test driven development so I wrote a test that will package the content of a directory and then verify that one file was packed.

It looks like this:

src/test/java/se/thinkcode/zip/ZipFileTest.java

package se.thinkcode.zip;

import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.junit.Test;

import java.io.*;
import java.util.Collection;
import java.util.Enumeration;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

public class ZipFileTest {

    @Test
    public void add_all_files_from_a_directory_to_a_zip_archive() throws Exception {
        File source = new File("build/resources/test");
        File destination = new File("build/resources.zip");
        destination.delete();

        addFilesToZip(source, destination);

        assertTrue("Expected to find the zip file ", destination.exists());
        assertZipContent(destination);
    }

    /**
     * Add all files from the source directory to the destination zip file
     *
     * @param source      the directory with files to add
     * @param destination the zip file that should contain the files
     * @throws IOException      if the io fails
     * @throws ArchiveException if creating or adding to the archive fails
     */
    private void addFilesToZip(File source, File destination) throws IOException, ArchiveException {
        OutputStream archiveStream = new FileOutputStream(destination);
        ArchiveOutputStream archive = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, archiveStream);

        Collection<File> fileList = FileUtils.listFiles(source, null, true);

        for (File file : fileList) {
            String entryName = getEntryName(source, file);
            ZipArchiveEntry entry = new ZipArchiveEntry(entryName);
            archive.putArchiveEntry(entry);

            BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));

            IOUtils.copy(input, archive);
            input.close();
            archive.closeArchiveEntry();
        }

        archive.finish();
        archiveStream.close();
    }

    /**
     * Remove the leading part of each entry that contains the source directory name
     *
     * @param source the directory where the file entry is found
     * @param file   the file that is about to be added
     * @return the name of an archive entry
     * @throws IOException if the io fails
     */
    private String getEntryName(File source, File file) throws IOException {
        int index = source.getAbsolutePath().length() + 1;
        String path = file.getCanonicalPath();

        return path.substring(index);
    }

    private void assertZipContent(File destination) throws IOException {
        ZipFile zipFile = new ZipFile(destination);

        ZipArchiveEntry readme = zipFile.getEntry("readme.txt");
        assertNotNull(readme);

        Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
        int numberOfEntries = 0;
        while (entries.hasMoreElements()) {
            numberOfEntries++;
            entries.nextElement();
        }
        assertThat(numberOfEntries, is(1));
    }
}

The work is done in addFilesToZip.

I like the idea of Tdd as if you meant it and this was the result from my implementation. Your job, if you want to use this solution, is to extract the methods needed and possibly modify them to suit you needs.

Building

Building this project requires you to have Gradle installed. When you have installed a modern version of Gradle, 2.6 when this is written, you build the example by executing

    gradle test

in the same directory as you have build.gradle. The dependencies needed will be downloaded and the test that packages one file will be executed.

Resources



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
Executable specification
Gradle
Guice
J2EE
JUnit
Java
Linux
Load testing
Maven
Mockito
Pair programming
PicoContainer
Programming
Public speaking
Quality
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS