Compresser un répertoire en fichier zip

Comment compresser un répertoire dans un fichier zip ?

Lire le contenu d’un répertoire

Un répertoire, comme un fichier, est représenté par une instance de java.io.File. On peut parcourir l’ensemble de ses fichiers avec la méthode listFiles(), en excluant les répertoires.

File directory = new File(...);
File[] allFiles = directory.listFiles(File::isFile);
for (File file : allFiles) {
  //...
}

Pour lire le contenu d’un fichier, on utilise un FileInputStream, puis on lit chaque byte par byte ou, pour optimiser, par paquets de bytes.

FileInputStream inputStream = new FileInputStream(file);
int data;
while ((data = inputStream.read()) >= 0) {
  //...
}

Ecrire un fichier Zip

Pour écrire un fichier Zip, il faut assembler un FileOutputStream à un ZipOutputStream.

File zipFile = new File(directory.getName() + ".zip");
FileOutputStream fOut = new FileOutputStream(zipFile);
ZipOutputStream zOut = new ZipOutputStream(fOut);

Pour chaque fichier, on doit créer une entrée du fichier zip, avant d’écrire des bytes, puis de fermer l’entrée.

// Déclaration de la première entrée de l'archive
zOut.putNextEntry(new ZipEntry(file.getName()));
int data;
while ((data = inputStream.read()) >= 0) {
  zOut.write(data);
}
zOut.closeEntry();

Exemple complet

Si on assemble tout ces éléments, on peut faire fonctionner cet exemple, pour un répertoire à 1 seul niveau de profondeur.

package fr.sewatech.formation.io;

import java.io.*;
import java.util.zip.*;

public class ZipDirExample {
  public static void main(String[] args) throws IOException {
    System.out.println(writeZip(new File("nio")));
  }

  public static File writeZip(File directory) throws IOException {
    // Si ce n'est pas un répertoire...
    File[] allFiles = directory.listFiles(File::isFile);
    if (!directory.isDirectory() || allFiles == null) {
      return null;
    }

    File zipFile = new File(directory.getName() + ".zip");
    try (ZipOutputStream zOut
            = new ZipOutputStream(new FileOutputStream(zipFile))) {
      for (File file : allFiles) {
        // Flux de lecture du fichier
        FileInputStream inputStream = new FileInputStream(file);

        // Déclaration de la première entrée de l'archive
        zOut.putNextEntry(new ZipEntry(file.getName()));
        int data;
        while ((data = inputStream.read()) >= 0) {
          zOut.write(data);
        }
        zOut.closeEntry();
      }
      return zipFile;
    }
  }
}

Conclusion

Avec un peu de récursivité, on peut traiter le cas d’un répertoire contenant d’autres répertoires…​