All formats

Apache Commons Compress

LanguageJava (8+)
LicenseApache 2.0
Repositorygithub.com/apache/commons-compress
DocumentationZIP package guide, user guide
Depends onCommons IO, Commons Lang; optional zstd-jni (Zstandard), XZ for Java
Read / writeyes / yes, ZIP64, stored and DEFLATE, Zstandard (1.28+); reads bzip2, Deflate64, Shrink, Implode; no encryption

Commons Compress handles many archive formats (ZIP, tar, 7z, ar, arj, cpio, dump) and compressors (gzip, bzip2, xz, Zstandard, LZ4, Brotli). Its ZIP support goes beyond java.util.zip:

It can’t read or write encrypted entries; canReadEntryData tells you if an entry is encrypted or uses an unsupported method.

Installation#

Maven:

XML
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.28.0</version>
</dependency>

Gradle:

implementation("org.apache.commons:commons-compress:1.28.0")

Basic usage: extract a ZIP file#

Java
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.Enumeration;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;

public class Unzip {
    public static void main(String[] args) throws IOException {
        Path target = Path.of("out").toAbsolutePath().normalize();
        try (ZipFile zip = ZipFile.builder().setFile("in.zip").get()) {
            Enumeration<ZipArchiveEntry> entries = zip.getEntries();
            while (entries.hasMoreElements()) {
                ZipArchiveEntry entry = entries.nextElement();
                Path dest = target.resolve(entry.getName()).normalize();
                if (!dest.startsWith(target)) throw new IOException("bad entry: " + entry.getName());
                if (!zip.canReadEntryData(entry)) {
                    System.err.println("skipping encrypted or unsupported entry " + entry.getName());
                    continue;
                }
                if (entry.isDirectory()) {
                    Files.createDirectories(dest);
                    continue;
                }
                Files.createDirectories(dest.getParent());
                try (InputStream in = zip.getInputStream(entry)) {
                    Files.copy(in, dest, StandardCopyOption.REPLACE_EXISTING);
                }
                System.out.printf("%s  mode %o%n", entry.getName(), entry.getUnixMode());
            }
        }
    }
}

How to create a ZIP file with Unix permissions#

Java
import java.io.IOException;
import java.nio.file.*;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;

public static void writeZip() throws IOException {
    try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(Path.of("out.zip"))) {
        zos.setLevel(9);
        zos.setUseZip64(Zip64Mode.AsNeeded);  // the default

        ZipArchiveEntry script = new ZipArchiveEntry(Path.of("run.sh"), "bin/run.sh");
        script.setUnixMode(0100755);  // regular file, rwxr-xr-x
        zos.putArchiveEntry(script);
        Files.copy(Path.of("run.sh"), zos);
        zos.closeArchiveEntry();

        zos.finish();
    }
}

How to write a Zstandard-compressed entry#

Needs the com.github.luben:zstd-jni dependency:

Java
import org.apache.commons.compress.archivers.zip.ZipMethod;

ZipArchiveEntry entry = new ZipArchiveEntry("data.csv");
entry.setMethod(ZipMethod.ZSTD.getCode());  // method 93
zos.putArchiveEntry(entry);
Files.copy(Path.of("data.csv"), zos);
zos.closeArchiveEntry();

Only some tools read Zstandard ZIP entries (7-Zip, WinZip, recent libzip); use DEFLATE for archives you share.

How to create a split ZIP archive#

Java
long partSize = 100L * 1024 * 1024;  // 100 MB parts: out.z01, out.z02, ..., out.zip
try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(Path.of("out.zip"), partSize)) {
    ZipArchiveEntry entry = new ZipArchiveEntry(Path.of("big.iso"), "big.iso");
    zos.putArchiveEntry(entry);
    Files.copy(Path.of("big.iso"), zos);
    zos.closeArchiveEntry();
}

To read a split archive, open the parts with ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(new File("out.zip")) and pass the channel to ZipFile.builder().setSeekableByteChannel(...).

Tips#