Fechando e descompactando em Java

Fechando e descompactando em Java

1. Visão geral

Neste tutorial rápido, discutiremos como compactar um arquivo em um arquivo e como descompactar o arquivo - tudo usando bibliotecas básicas fornecidas por Java.

Essas bibliotecas centrais são parte do pacotejava.util.zip - onde podemos encontrar todos os utilitários relacionados à compactação e descompactação.

2. Compactar um arquivo

Vamos primeiro dar uma olhada em uma operação simples - compactar um único arquivo.

Para nosso exemplo aqui, vamos compactar um arquivo chamadotest1.txt em um arquivo chamadocompressed.zip. __

Obviamente, primeiro acessaremos o arquivo do disco - vamos dar uma olhada:

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. Compactar vários arquivos

A seguir, vamos ver como compactar vários arquivos em um arquivo compactado. Comprimiremostest1.txtetest2.txt emmultiCompressed.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. Compacte um diretório

Agora, vamos discutir como compactar um diretório inteiro. Iremos diretóriozipTest emdirCompressed.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();
    }
}

Observe que:

  • Para compactar subdiretórios, iteramos através deles recursivamente.

  • Cada vez que encontramos um diretório, acrescentamos seu nome ao nome dos descendentesZipEntry para salvar a hierarquia.

  • Também criamos uma entrada de diretório para cada diretório vazio

5. Descompacte um arquivo

Vamos agora descompactar um arquivo e extrair seu conteúdo.

Para este exemplo, vamos descompactarcompressed.zip em uma nova pasta chamadaunzipTest.

Vamos dar uma olhada:

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;
    }
}

Outro ponto chave pode ser visto no métodonewFile(). Esse método protege contra a gravação de arquivos no sistema de arquivos fora da pasta de destino. Esta vulnerabilidade é chamada de Zip Slip e você poderead more about it here.

6. Conclusão

Este tutorial ilustrou como é simples o uso de bibliotecas Java para operações de compactar e descompactar arquivos.

A implementação desses exemplos pode ser encontradaover on GitHub - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.