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á.