Compression et décompression en Java

Compression et décompression en Java

1. Vue d'ensemble

Dans ce rapide didacticiel, nous verrons comment compresser un fichier dans une archive et comment décompresser l'archive, le tout à l'aide des bibliothèques principales fournies par Java.

Ces bibliothèques de base font partie du packagejava.util.zip - où nous pouvons trouver tous les utilitaires liés à la compression et à la décompression.

2. Compresser un fichier

Examinons d'abord une opération simple: compresser un seul fichier.

Pour notre exemple ici, nous allons compresser un fichier nommétest1.txt dans un fichier nommécompressed.zip archivé. __

Nous allons bien sûr d'abord accéder au fichier à partir du disque - voyons:

public class ZipFile {
    public static void main(String[] args) throws IOException {
        String sourceFile = "test1.txt";
        FileOutputStream fos = new FileOutputStream("compressed.zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        File fileToZip = new File(sourceFile);
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        zipOut.close();
        fis.close();
        fos.close();
    }
}

3. Compresser plusieurs fichiers

Voyons ensuite comment compresser plusieurs fichiers en un seul fichier zip. Nous allons compressertest1.txt ettest2.txt enmultiCompressed.zip:

public class ZipMultipleFiles {
    public static void main(String[] args) throws IOException {
        List srcFiles = Arrays.asList("test1.txt", "test2.txt");
        FileOutputStream fos = new FileOutputStream("multiCompressed.zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        for (String srcFile : srcFiles) {
            File fileToZip = new File(srcFile);
            FileInputStream fis = new FileInputStream(fileToZip);
            ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
            zipOut.putNextEntry(zipEntry);

            byte[] bytes = new byte[1024];
            int length;
            while((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }
            fis.close();
        }
        zipOut.close();
        fos.close();
    }
}

4. Zip un répertoire

Voyons maintenant comment compresser un répertoire entier. Nous allons répertoirezipTest dansdirCompressed.zip:

public class ZipDirectory {
    public static void main(String[] args) throws IOException {
        String sourceFile = "zipTest";
        FileOutputStream fos = new FileOutputStream("dirCompressed.zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        File fileToZip = new File(sourceFile);

        zipFile(fileToZip, fileToZip.getName(), zipOut);
        zipOut.close();
        fos.close();
    }

    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        fis.close();
    }
}

Notez que:

  • Pour compresser des sous-répertoires, nous les parcourons de manière récursive.

  • Chaque fois que nous trouvons un répertoire, nous ajoutons son nom au nom des descendantsZipEntrypour sauvegarder la hiérarchie.

  • Nous créons également une entrée de répertoire pour chaque répertoire vide

5. Décompressez une archive

Décompressons maintenant une archive et extrayons son contenu.

Pour cet exemple, nous allons décompressercompressed.zip dans un nouveau dossier nomméunzipTest.

Regardons:

public class UnzipFile {
    public static void main(String[] args) throws IOException {
        String fileZip = "src/main/resources/unzipTest/compressed.zip";
        File destDir = new File("src/main/resources/unzipTest");
        byte[] buffer = new byte[1024];
        ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
        ZipEntry zipEntry = zis.getNextEntry();
        while (zipEntry != null) {
            File newFile = newFile(destDir, zipEntry);
            FileOutputStream fos = new FileOutputStream(newFile);
            int len;
            while ((len = zis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
            fos.close();
            zipEntry = zis.getNextEntry();
        }
        zis.closeEntry();
        zis.close();
    }

    public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
        File destFile = new File(destinationDir, zipEntry.getName());

        String destDirPath = destinationDir.getCanonicalPath();
        String destFilePath = destFile.getCanonicalPath();

        if (!destFilePath.startsWith(destDirPath + File.separator)) {
            throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
        }

        return destFile;
    }
}

Un autre point clé peut être vu dans la méthodenewFile(). Ces méthodes évitent d'écrire des fichiers dans le système de fichiers en dehors du dossier cible. Cette vulnérabilité s'appelle Zip Slip et vous pouvezread more about it here.

6. Conclusion

Ce tutoriel illustre la simplicité d'utilisation des bibliothèques Java pour les opérations de compression et de décompression de fichiers.

La mise en œuvre de ces exemples peut être trouvéeover on GitHub - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.