All formats

java.util.zip

LanguageJava
LicenseGPL v2 with Classpath Exception (part of OpenJDK)
Repositorygithub.com/openjdk/jdk
Documentationjava.util.zip package, ZIP file system provider
Depends onnothing (built into the JDK)
Read / writeyes / yes, ZIP64, stored and DEFLATE; no encryption

The JDK has three ways to work with ZIP files:

All support ZIP64 and UTF-8 names (the default charset for names is UTF-8; pass another Charset for old archives). There’s no support for encryption or compression methods other than stored and DEFLATE. JAR files are read with the same classes (java.util.jar extends them).

Installation#

Nothing to install: part of every JDK.

Basic usage: list and extract a ZIP file#

Java
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class Unzip {
    public static void main(String[] args) throws IOException {
        Path target = Path.of("out").toAbsolutePath().normalize();
        try (ZipFile zip = new ZipFile("in.zip")) {
            Enumeration<? extends ZipEntry> entries = zip.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                System.out.printf("%-40s %10d -> %10d%n", entry.getName(), entry.getSize(), entry.getCompressedSize());

                Path dest = target.resolve(entry.getName()).normalize();
                if (!dest.startsWith(target)) {  // Zip Slip protection
                    throw new IOException("bad entry name: " + entry.getName());
                }
                if (entry.isDirectory()) {
                    Files.createDirectories(dest);
                } else {
                    Files.createDirectories(dest.getParent());
                    try (InputStream in = zip.getInputStream(entry)) {
                        Files.copy(in, dest, StandardCopyOption.REPLACE_EXISTING);
                    }
                }
            }
        }
    }
}

How to create a ZIP file from a folder#

Java
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.*;
import java.util.stream.Stream;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public static void zipFolder(Path folder, Path zipPath) throws IOException {
    try (OutputStream os = Files.newOutputStream(zipPath);
         ZipOutputStream zos = new ZipOutputStream(os);
         Stream<Path> files = Files.walk(folder)) {
        zos.setLevel(Deflater.BEST_COMPRESSION);
        for (Path p : (Iterable<Path>) files.filter(Files::isRegularFile)::iterator) {
            // entry names always use '/', relative to the folder
            String name = folder.relativize(p).toString().replace('\\', '/');
            zos.putNextEntry(new ZipEntry(name));
            Files.copy(p, zos);
            zos.closeEntry();
        }
    }
}

How to read one file from a ZIP#

Java
try (ZipFile zip = new ZipFile("in.zip")) {
    ZipEntry entry = zip.getEntry("docs/readme.txt");
    if (entry != null) {
        try (InputStream in = zip.getInputStream(entry)) {
            String text = new String(in.readAllBytes(), StandardCharsets.UTF_8);
            System.out.println(text);
        }
    }
}

How to add a file to an existing ZIP (ZIP file system)#

Java
import java.net.URI;
import java.nio.file.*;
import java.util.Map;

Path zipPath = Path.of("existing.zip");
try (FileSystem fs = FileSystems.newFileSystem(zipPath, Map.of("create", "true"))) {
    Files.copy(Path.of("notes.txt"), fs.getPath("/notes.txt"), StandardCopyOption.REPLACE_EXISTING);
    Files.writeString(fs.getPath("/hello.txt"), "hello from zipfs");
    Files.deleteIfExists(fs.getPath("/old.log"));
}  // the archive is rewritten on close

"create", "true" creates the archive if it doesn’t exist.

How to read a ZIP from a stream#

Java
try (ZipInputStream zis = new ZipInputStream(inputStream)) {
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
        System.out.println(entry.getName());
        byte[] data = zis.readAllBytes();  // reads only the current entry
    }
}

Tips#