Compactando e descompactando arquivos em Java
Em muitos casos necessitamos manipular arquivos compactados, sendo criando arquivos compactados no formato zip ou descompactando para para leitura. Para estas funcionalidades o Java nos fornece a classe ZipOutputStream
.
Vamos ao código, primeiro compactamos uma String qualquer:
String texto = "Um texto qualquer vindo de algum lugar!" ;
try {
FileOutputStream fileOut = new FileOutputStream("texto.zip");
ZipOutputStream out = new ZipOutputStream(fileOut);
out.putNextEntry( new ZipEntry("texto.txt") );
out.write( texto.getBytes() );
out.closeEntry();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
Na linha 4 criamos um objeto FileOutputStream
que é um fluxo de saída para um arquivo onde iremos gravar nossos dados compactados. Utilizaremos este objeto para criarmos nosso objeto ZipOutputStream
onde ao escrevermos no ZipOutputStream
ele irá compactar e passar os dados para o FileOutputStream
que irá gravar no arquivo.
Na linha 7 criamos uma nova entrada no arquivo compactado(ou seja um arquivo dentro do zip), a partir deste ponto todos os dados que escrevermos no ZipOutputStream
será compactado para dentro deste arquivo, o que fazemos na linha 8 pegando o texto em formato de array de bytes através do método geBytes()
. Na linha 9 fechamos a entrada do arquivo compactado, se quisermos podemos chamar novamente putNextEntry()
para criar um novo arquivo dentro do zip. Na linha 10 fechamos o arquivo compactado através do método close.
Vamos ver agora como compactar um arquivo do HD:
try {
FileInputStream fis = new FileInputStream("arquivo.txt");
FileOutputStream fos = new FileOutputStream("arquivo.zip");
ZipOutputStream zipOut = new ZipOutputStream( fos );
zipOut.putNextEntry( new ZipEntry("arquivo.txt") );
int content;
while ((content = fis.read()) != -1) {
zipOut.write(content );
}
zipOut.closeEntry();
zipOut.close();
} catch (IOException e) {
e.printStackTrace();
}
Como podemos ver a diferença é pequena apenas criamos um objeto FileInputStream
com o arquivo que queremos compactar na linha 2. A partir da linha 9 começamos a leitura do arquivo, no laço while
chamamos o método read()
de FileInputStream
que retornará um int
do arquivo, que atribuímos para content
, se esta operação retornar qualquer coisa que não for “-1”
(ou seja a operação funcionou e existia conteúdo dentro do arquivo) pegamos o valor de content
e colocamos dentro do arquivo compactado na linha 11. Após isso somente fechamos o arquivo compactado.
Vamos agora a um exemplo de como compactar uma pasta inteira;
try {
FileOutputStream fos = new FileOutputStream("pasta.zip");
ZipOutputStream zipOut = new ZipOutputStream( fos );
File pasta = new File("pasta");
for(File arq : pasta.listFiles() ){
zipOut.putNextEntry( new ZipEntry( arq.getName().toString() ) );
FileInputStream fis = new FileInputStream( arq );
int content;
while ((content = fis.read()) != -1) {
zipOut.write( content );
}
zipOut.closeEntry();
}
zipOut.close();
} catch (IOException e) {
e.printStackTrace();
}
Basicamente o que fazemos é listar todos os arquivos da pasta(linha 7) e adicionar arquivo por arquivo da pasta no arquivo zip.
Agora vamos ver como ler um arquivo compactado
try {
FileInputStream fis = new FileInputStream("arquivo.zip");
ZipInputStream zipIn = new ZipInputStream( fis );
ZipEntry entry = zipIn.getNextEntry();
while (zipIn.available() > 0){
System.out.print( (char) zipIn.read() );
}
} catch (IOException e) {
e.printStackTrace();
}
Agora ao invés de utilizamos um objeto ZipOutputStream
utilizaremos um objeto ZipInputStream
para leitura, objeto que criamos passando para seu construtor um FileInputStream
ou seja um fluxo de entrada. Na linha 6 pegamos o objeto que representa a próxima entrada do arquivo compactado, no nosso caso a primeira e única. Ao chamar getNextEntry()
o fluxo de leitura será posicionado na posição do próximo arquivo dentro do zip, então se chamarmos diversas vezes seguidas este métodos estaremos saltando arquivos que estão no mesmo arquivo zip.
Na linha 8 temos um laço while
que irá executar enquanto o retorno do método available()
for maior que “0”, sendo que este valor representa a quantidade de bytes que pode ser lido do fluxo do entrada, detalhe, não é o que resta ainda do arquivo para ser lido, mas o que pode ser lido na próxima chamada. Na linha 9 pegamos o próximo byte do fluxo no nosso caso convertemos para char
para ser exibido como texto na tela. Após sair do laço poderíamos chamar novamente getNextEntry()
para pegarmos a próxima entrada e ler o próximo arquivo que esta dentro do arquivo zip.
Como você pode ter percebido nos nossos exemplos não escrevemos e lemos de forma muito eficiente mas espero que tenha dado para ter uma ideia do processo, o que necessita de algum conhecimento sobre as Stream do Java.
Mais detalhes sobre as classes pode ser visto na documentação ZipOutputStream, ZipInputStream e ZipEntry.
Por isso era hoje pessoal ?!?