sexta-feira, 30 de dezembro de 2011

Geração de arquivo zip

Arquivos com formato ZIP são armazenados em um único arquivo compactados (ou diversos arquivos parciais). O framework do Java é capaz de gerar arquivos nos formatos GZIP e ZIP conforme definições das RFC 1950, RFC 1951 e RFC 1952.
As classes que manipulam arquivos ZIP estão em java.util.zip. Estas classes são subclasses de java.io.FilterInputStream e java.io.FilterOutputStream. Desta forma a geração de um arquivo lembra bastante a manipulação de uma stream.
Neste pacote encontramos ainda classe para gerar CRC (cyclic redundancy check checksums).
Um arquivo .zip  possui um cabeçalho com informações com o nome dos arquivos e métodos de compressão utilizados. Podemos utilizar ZipInputStream para ler o arquivo zip utilizando construção abaixo:


// encadear a chamada para ZipInputStream com FileInputStream
FileInputStream arquivo = new FileInputStream(nomeDoArquivoZip)
ZipInputStream arquivoZip = new ZipInputStream(arquivo);
ZipEntry arquivoCompactado;
// varre o arquivo compactado buscando cada uma das entradas
while ((
arquivoCompactado = arquivoZip.getNextEntry()) != null) {
   /*
   arquivoCompactado.toString() --> retorna uma string representando a entrada
   arquivoCompactado.getName() --> retorna o nome da entrada (arquivo/diretorio)
   arquivoCompactado.isDirectory() --> retorna se a entrada é um diretório
   arquivoCompactado.getTime()  --> hora da arquivo (entrada)
   arquivoCompactado.getSize()  --> tamanho do arquivo (entrada) descompactado
   arquivoCompactado.getCRC()   --> CRC
   arquivoCompactado.CompressedSize() --> tamanho do arquivo compactado
   */
   arquivoCompactado.closeEntry();
}
arquivoCompactado.close();


Vamos ver um exemplo mais completo que lista os arquivos contidos em um zip.

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;


public class ExemploZipInput {


 // entrada do programa
 public static void main(String[] args) {
   ExemploZipInputFrame frame = new ExemploZipInputFrame();
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.setVisible(true);
 }
} // ExemploZipInput


/**
  Esta classe é composta por uma área que apresenta os arquivos texto
  e permite a descompactação. O arquivo zip pode ser selecionado pelo menu.
*/
class ExemploZipInputFrame extends JFrame {
  // tamanho da tela
  public static final int DEFAULT_WIDTH = 600
  public static final int DEFAULT_HEIGHT = 400;


  private JComboBox<String> comboArquivosNoZip;
  private JTextArea areaArquivoTexto; // local para apresentar os arquivos texto
  private JButton btnExtrair; // 
  private String nomeArquivoZip;
  
  public ExemploZipInputFrame() {
    setTitle("Exemplo de utilizacao de java.util.zip");
    setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

    // menu
    JMenuBar menuBar = new JMenuBar();
    // 1. Arquivo
    JMenu menu = new JMenu("Arquivo"); 
    JMenuItem mnuAbrir = new JMenuItem("Abrir");
    menu.add(mnuAbrir);
    mnuAbrir.addActionListener(new ActionAbrirZip()); // classe definida abaixo
    JMenuItem mnuSair = new JMenuItem("Sair");
    menu.add(mnuSair);
    mnuSair.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) { System.exit(0); }
    });
    menuBar.add(menu);
    setJMenuBar(menuBar);


    // adiciona componentes no Frame
    areaArquivoTexto = new JTextArea();
    comboArquivosNoZip = new JComboBox<String>();
    comboArquivosNoZip.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
String nomeArquivo = (String) comboArquivosNoZip.getSelectedItem();
if (nomeArquivo.endsWith(".txt") || nomeArquivo.endsWith(".java")) {
         carregaArquivoNaTextArea(nomeArquivo);
}
      }
    });

    add(comboArquivosNoZip, BorderLayout.NORTH);
    add(new JScrollPane(areaArquivoTexto), BorderLayout.CENTER);
    btnExtrair = new JButton("Extrair");
    btnExtrair.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
// descompacta o conteudo
        descompactaArquivo((String) comboArquivosNoZip.getSelectedItem());
      }
    });
   add(btnExtrair, BorderLayout.SOUTH);
  } // Construtor ExemploZipInputFrame

  /**
   Classe que realiza ação de "Abrir" do menu
  */
  private class ActionAbrirZip implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      // seleciona o arquivo Zip
      JFileChooser arquivoEscolhido = new JFileChooser();
      arquivoEscolhido.setCurrentDirectory(new File("."));
      FiltrosDeArquivos filtro = new FiltrosDeArquivos();
      filtro.adicionarExtensao(".zip");
      filtro.adicionarExtensao(".jar");
      filtro.setDescription("Arquivos ZIP");
      arquivoEscolhido.setFileFilter(filtro);
      int escolha = arquivoEscolhido.showOpenDialog(ExemploZipInputFrame.this);
      if (escolha == JFileChooser.APPROVE_OPTION) {
        nomeArquivoZip = arquivoEscolhido.getSelectedFile().getPath();
        ProcuraNoArquivoZip();
      }
    }
  } // ActionAbrirZip


  /**
    Lista entradas do arquivo ZIP e preenche o conteudo no combobox
  */
  public void ProcuraNoArquivoZip() {
    comboArquivosNoZip.removeAllItems();
     try {
       ZipInputStream arquivoZip =
        new ZipInputStream(new FileInputStream(nomeArquivoZip));
       ZipEntry entradaNoZip = null;
       while ((entradaNoZip = arquivoZip.getNextEntry()) != null) {
         comboArquivosNoZip.addItem(entradaNoZip.getName());
         arquivoZip.closeEntry();
       }
       arquivoZip.close();
     } catch (IOException e) {
       e.printStackTrace();
     }
  }


  /**
     Lê o conteúdo do arquivo para a área
     @param nome do arquivo compactado (entrada do zip)
   */
   public void carregaArquivoNaTextArea(String nome) {
     BufferedReader arquivoLido = null;
 
     try {
       areaArquivoTexto.setText(""); // apaga o conteudo da área de texto
       ZipInputStream arquivoZip =
         new ZipInputStream(new FileInputStream(nomeArquivoZip));
       ZipEntry entradaNoZip = null;
       // varre as entradas
       // acha entrada = "nome"
       while ((entradaNoZip = arquivoZip.getNextEntry()) != null) {
 if (entradaNoZip.getName().equals(nome)) {
   // se achou ... le para área de texto
   arquivoLido = new BufferedReader(new InputStreamReader(arquivoZip));
   String linhaLida;
   while ((linhaLida = arquivoLido.readLine()) != null) {
     areaArquivoTexto.append(linhaLida);
     areaArquivoTexto.append("\n");
   }
}
         arquivoZip.closeEntry();  
       }
       arquivoZip.close();
     } catch (IOException e) {
       e.printStackTrace();
     }
   }


   public void descompactaArquivo(String nome) {
     try {
       areaArquivoTexto.setText(""); // apaga o conteudo da área de texto
       ZipInputStream arquivoZip =
          new ZipInputStream(new FileInputStream(nomeArquivoZip));
       ZipEntry entradaNoZip = null;
       // acha entrada = "nome"
       while ((entradaNoZip = arquivoZip.getNextEntry()) != null) {
         if (entradaNoZip.getName().equals(nome)) {
           BufferedOutputStream arquivoDescompactado =
             new BufferedOutputStream(new FileOutputStream(nome));
           for(int i = arquivoZip.read(); i != -1; i = arquivoZip.read() ) {
     arquivoDescompactado.write(i);
   }
   arquivoDescompactado.close();
 }
 arquivoZip.closeEntry();
       }
       arquivoZip.close();
     } catch (IOException e) {
       e.printStackTrace();
     }
   }


   
} // ExemploZipInputFrame


/**
  Esta classe cria um filtro para localizar os arquivos texto
  Utilizado em JFileChooser quando tenta selecionar um arquivo em ABRIR
*/
class FiltrosDeArquivos extends FileFilter {


   private String descricao = "";
   // guarda a lista de extensões suportadas
   private ArrayList<String> extensoesArquivos = new ArrayList<String>();


  /**
     adiciona uma extensão no filtro
     @param extensão do arquivo tipo ".txt" ou "txt"
  */
   public void adicionarExtensao(String e) {
     if (!e.startsWith(".")) { // acrescenta o ponto
        e = "." + e;
     }
     extensoesArquivos.add(e.toLowerCase());
   }


   /**
      Armazena a descrição
      @param desc: uma descricao para o conjunto de filtros
   */
   public void setDescription(String desc) { descricao = desc; }


   /**
      Returna a descricao
      @return descricao
   */
   public String getDescription() { return descricao; }


   /**
      Indica que pode selecionar a entrada
   */
   public boolean accept(File f) {
     if (f.isDirectory()) return true;
     String name = f.getName().toLowerCase();


     // verifica se a extensão passa no filtro
     for (String e : extensoesArquivos) {
       if (name.endsWith(e)) return true;
     }
     return false; // não achou
   }


}

Vamos ver como ficou:



Um comentário:

  1. Se voces tentaram compilar a calsse acima no framework menor que jdk 1.7 vai receber um erro de compilacao. Isto acontece porque a partir do SE 7 a definicao de JComboBox eh
    public class JComboBox
    onde E representa o tipo de objeto que compoe a lista do combo. Em SE 6 a declaracao eh somente JComboBox.

    ResponderExcluir