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.
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 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 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.