Blog da Softblue


Este artigo foi criado por Carlos Eduardo Gusso Tosin.
Conheça o currículo completo do instrutor clicando aqui.

Zip/Unzip em Java

Publicado em 10/03/2010 às 10:13:13 horas.

Compartilhe:    

Olá pessoal, hoje vamos falar sobre zip e unzip em Java, pois a compactação de dados está amplamente presente em sistemas, serviços e aplicativos. Quem nunca precisou compactar arquivos para mandar para alguém, ou então compactar dados para trafegarem pela rede?

Neste tópico apresentarei uma maneira fácil para compactar e descompactar arquivos no formato ZIP utilizando Java. Java possui suporte a arquivos ZIP, logo não é necessário utilizar nenhuma API extra. As classes estão localizadas dentro do pacote java.util.zip. As classes principais desse pacote são: ZipEntry, ZipFile, ZipInputStream e ZipOutputStream. Para demonstrar como a compactação e descompactação funcionam, vou mostrar a criação de uma classe com dois métodos: zip() e unzip(). Todo o "trabalho sujo" fica por conta da classe. O código-fonte pode ser visualizado no final desta explicação.

Vamos começar pelo método zip(). O método zip() recebe dois parâmetros: o primeiro é a lista de arquivos a serem zipados; e o segundo é o arquivo ZIP que será gerado. O código deste método é bastante simples porque toda a lógica de compactação se encontra no método zipFiles().

O método zipFiles() é reponsável por iterar sobre a lista de arquivos e adicioná-los ao arquivo ZIP de saída. Esta tarefa seria simples, mas às vezes queremos compactar não apenas arquivos, mas também estruturas de diretórios dentro do nosso arquivo ZIP. E para manter essa estrutura de diretórios de forma correta, devemos programar este comportamento manualmente.

Observe que, caso uma das entradas que deve aparecer no arquivo ZIP seja um diretório, o método zipFiles() é chamado recursivamente, passando como parâmetro a lista de arquivos do diretório. Esta abordagem possibilita que o método processe todos os arquivos de cada diretório, de uma forma semelhante à busca em profundidade que aprendemos nas aulas de Estruturas de Dados. Junto com a lista de arquivos, também é fornecida uma pilha com os nomes dos diretórios onde o arquivo se encontra. Essa informação é utilizada na reconstrução do caminho do arquivo dentro do arquivo ZIP.

Já para descompactar, temos o método unzip(). O método unzip() recebe dois parâmetros: o arquivo ZIP a ser descompactado e um diretório para a descompactação. No caso da descompactação é feito o caminho inverso da compactação. Cada entrada do arquivo ZIP é lida e gravada no sistema de arquivos. Caso a entrada seja um diretório, a estrutura de diretórios deve primeiramente ser criada e só então o arquivo deve ser descompactado (o Java não cria os diretórios automaticamente, ficando a cargo do programador garantir a criação dos diretórios necessários).

Esses dois métodos representam uma solução básica e bem completa para compactar e descompactar arquivos. Recomendo que você inclua esta funcionalidade em um componente, a fim de que possa ser usado em diferentes projetos.

Código-fonte utilizado no artigo:


package zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Stack;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class ZipHelper {

	public void zip(File[] files, File outputFile) throws IOException {

		if (files != null && files.length > 0) {
			ZipOutputStream out = new ZipOutputStream(
						new FileOutputStream(outputFile));
			Stack<File> parentDirs = new Stack<File>();
			zipFiles(parentDirs, files, out);
			out.close();
		}
	}

	private void zipFiles(Stack<File> parentDirs, File[] files, 
				ZipOutputStream out) throws IOException {
		byte[] buf = new byte[1024];

		for (int i = 0; i < files.length; i++) {
			if (files[i].isDirectory()) {
				//se a entrad é um diretório, empilha o diretório e 
				//chama o mesmo método recursivamente
				parentDirs.push(files[i]);
				zipFiles(parentDirs, files[i].listFiles(), out);
				
				//após processar as entradas do diretório, desempilha
				parentDirs.pop();
			} else {
				FileInputStream in = new FileInputStream(files[i]);
				
				//itera sobre os itens da pilha para montar o caminho 
				//completo do arquivo
				String path = "";
				for(File parentDir : parentDirs) {
					path += parentDir.getName() + "/";
				}
				
				//grava os dados no arquivo zip
				out.putNextEntry(new ZipEntry(path + files[i].getName()));

				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}

				out.closeEntry();
				in.close();
			}
		}
	}
	
	public void unzip(File zipFile, File dir) throws IOException {
		ZipFile zip = null;
		File arquivo = null;
		InputStream is = null;
		OutputStream os = null;
		byte[] buffer = new byte[1024];
		
		try {
			// cria diretório informado, caso não exista
			if (!dir.exists()) {
				dir.mkdirs();
			}
			if (!dir.exists() || !dir.isDirectory()) {
				throw new IOException("O diretório " + dir.getName() + 
				" não é um diretório válido");
			}
			
			zip = new ZipFile(zipFile);
			Enumeration e = zip.entries();
			while (e.hasMoreElements()) {
				ZipEntry entrada = (ZipEntry) e.nextElement();
				arquivo = new File(dir, entrada.getName());
				
				// se for diretório inexistente, cria a estrutura e pula 
				// pra próxima entrada
				if (entrada.isDirectory() && !arquivo.exists()) {
					arquivo.mkdirs();
					continue;
				}
				
				// se a estrutura de diretórios não existe, cria
				if (!arquivo.getParentFile().exists()) {
					arquivo.getParentFile().mkdirs();
				}
				try {
					// lê o arquivo do zip e grava em disco
					is = zip.getInputStream(entrada);
					os = new FileOutputStream(arquivo);
					int bytesLidos = 0;
					if (is == null) {
						throw new ZipException("Erro ao ler a entrada do zip: " + 
									entrada.getName());
					}
					while ((bytesLidos = is.read(buffer)) > 0) {
						os.write(buffer, 0, bytesLidos);
					}
				} finally {
					if (is != null) {
						try {
							is.close();
						} catch (Exception ex) {
						}
					}
					if (os != null) {
						try {
							os.close();
						} catch (Exception ex) {
						}
					}
				}
			}
		} finally {
			if (zip != null) {
				try {
					zip.close();
				} catch (Exception e) {
				}
			}
		}
	}
}

Comentários

Parabéns pelo artigo! Funcionou perfeitamente para o que eu precisava.
Indico também: http://java.sun.com/developer/technicalArticles/Programming/compression/

Enviado em 16/04/2012 às 16:36:11 horas, por Filipe Santana

Mailing List

Cadastre o seu e-mail para receber notícias e informações sobre novos cursos, atualizações e outras novidades da Softblue!

Diferenciais

Liberdade total
Estude quando e como quiser. Disponibilidade do conteúdo 24h por dia, 7 dias por semana.
Matrícula não expira
Pagamento único, sem mensalidades, e acesso vitalício a todo o conteúdo, mesmo após a conclusão do curso.
Cursos sempre atualizados
Acesso às atualizações dos cursos de forma automática.
Tire suas dúvidas
Suporte eficiente para esclarecer suas dúvidas no decorrer do curso.
Padrão de qualidade
Atendimento diferenciado e material de alta qualidade, feito por quem entende do assunto.

Certificado

Insira o código do certificado que deseja consultar:

Pagamento





Conheça todas as nossas formas de pagamento.


             Cursos  |   Perguntas  |   Sobre nós  |   Sorteios  |   Blog  |   Política de Privacidade  |   Contato Desde 2003.    
Todos os direitos reservados ®    
CNPJ 06.860.085/0001-64