El JDK trae java.util.zip desde la versión 1.1, así que para hacer un ZIP no hace falta ninguna dependencia. La pieza es ZipOutputStream: se abre, se va añadiendo una entrada por archivo y se cierra.
También te puede interesar
Comprimir una carpeta entera
import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
public class CrearZip {
public static void main(String[] args) throws Exception {
Path carpeta = Path.of("origen");
Path zip = Path.of("copia.zip");
try (var salida = new ZipOutputStream(Files.newOutputStream(zip));
var rutas = Files.walk(carpeta)) {
salida.setLevel(Deflater.BEST_COMPRESSION);
rutas.filter(Files::isRegularFile).sorted().forEach(p -> {
try {
salida.putNextEntry(new ZipEntry(carpeta.relativize(p).toString()));
Files.copy(p, salida);
salida.closeEntry();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
System.out.println("creado " + zip + ", " + Files.size(zip) + " bytes");
}
}salidacreado copia.zip, 365 bytes
Las tres cosas que hay que hacer bien
1. La ruta de la entrada tiene que ser relativa. Ese carpeta.relativize(p) convierte origen/sub/c.txt en sub/c.txt. Si metes la ruta absoluta, el ZIP guarda /home/usuario/proyecto/origen/... dentro y al descomprimirlo en otro ordenador aparece un árbol de carpetas absurdo. Los ZIP usan siempre la barra /, también los creados en Windows.
2. Una entrada se abre y se cierra. putNextEntry y closeEntry van en pareja; entre medias se escribe el contenido, y Files.copy(p, salida) lo vuelca sin bucles.
3. El try (…) cierra el ZIP. Si no se cierra, el archivo queda truncado y ningún programa lo abre: la tabla de contenidos de un ZIP se escribe al final.
Comprobar lo que ha quedado dentro
try (var zf = new ZipFile(zip.toFile())) {
zf.stream().forEach(e -> System.out.printf(" %-14s %4d -> %4d bytes%n",
e.getName(), e.getSize(), e.getCompressedSize()));
}salidaa.txt 8 -> 10 bytes b.txt 8 -> 10 bytes sub/c.txt 7 -> 9 bytes
El nivel de compresión
| Valor | Qué hace |
|---|---|
Deflater.NO_COMPRESSION (0) | solo empaqueta, no comprime |
Deflater.DEFAULT_COMPRESSION (−1) | el equilibrio de serie |
Deflater.BEST_SPEED (1) | rápido y flojo |
Deflater.BEST_COMPRESSION (9) | lento y apretado |
Entre el 1 y el 9 la diferencia de tamaño suele ser de un 5 % y la de tiempo, de varias veces. Para un ZIP que se genera al vuelo en un servidor, el nivel por omisión es casi siempre la decisión correcta.
Comprimir desde memoria
var buffer = new ByteArrayOutputStream();
try (var zip = new ZipOutputStream(buffer)) {
zip.putNextEntry(new ZipEntry("informe.csv"));
zip.write(csv.getBytes(StandardCharsets.UTF_8));
zip.closeEntry();
}
byte[] descarga = buffer.toByteArray();Útil para devolver un ZIP desde una web sin dejar nada en disco. Si el contenido es grande, mejor escribir directamente en el OutputStream de la respuesta.
Más información en inglés: Create ZIP files in Java.
Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.