sábado, 31 de dezembro de 2011

Renomear arquivos

Vamos dizer que você baixou um torrent. Os arquivos do torrent foram todos acrescidos de um sufixo com o nome do uploader e os espaços foram trocados por "+".  Queremos retirar este sufixo e trocar os "+" por espaços.

import java.io.File;
import java.io.IOException;

/**
* renomeia um arquivo, remove um padrão e substitui por outro
* @param arg[0] arquivo ou diretorio
* @param arg[1] padrao a ser procurado
* @param arg[2] novo valor
* @param arg[3] opcional. se igual a "sub" procura nos subdiretórios
*/
public class RenomeiaArquivos {
  String padrao;
  String novoPadrao;
  boolean subDiretorios = false;

  public RenomeiaArquivos(String seq, String novaSeq, boolean sub) {
    padrao = seq;
    novoPadrao = novaSeq;
    subDiretorios = sub;
  }

  private String adequaString(String original) {
    return original.replace(padrao, novoPadrao);
  }

  private boolean renomeiaArquivo(File f) throws IOException {
    if (f.getName().contains(padrao)) {
      String novoNome = adequaString(f.getAbsolutePath());
      return f.renameTo(new File(novoNome));
    }
    return false;
  }

  private void renomeiaDiretorio(File f) throws IOException {
    String[] lista = f.list();
    File arq;
    for(int i=0; i < lista.length; i++) {
     arq = new File(lista[i]);
     if (arq.isFile()) {
       renomeiaArquivo(arq);
     } else if (subDiretorios) {
       System.out.println("Dir>"+arq.getName());
       renomeiaDiretorio(arq);
     }
    }
  }

  private void executar(String nomeArquivo) throws IOException {
    File f = new File(nomeArquivo);
    System.out.println("Renomeando "+f.getName());
    if (f.isFile()) {
      renomeiaArquivo(f);
    } else {
      renomeiaDiretorio(f);
    }
  }

  public static void main(String[] args) {

    if (args.length < 3) {
      System.out.println("Uso: java RenomeiaArquivos {nomeArquivo|nomeDiretorio} \"padrao original\" \"novo padrao\" [sub]");
      System.exit(0); // sair
    }

    boolean sub = (args.length > 3) && (args[3].equalsIgnoreCase("sub"));
    RenomeiaArquivos ren = new RenomeiaArquivos(args[1], args[2], sub);
    try {
      ren.executar(args[0]);
    } catch (IOException e) {
      System.out.println(e.toString());
    }
  }

}

Testem e descubram o erro deste programa.

Notem que ele compila e consegue ser executado. Este exemplo rodamos no linux com open-jdk.
Seria interessante que este programa utilize regex para podermos usar wildcard para o nome de arquivo.

sexta-feira, 30 de dezembro de 2011

Comparar datas de arquivos


Muitas vezes quando desejamos efetuar operações sobre arquivos, como por exemplo, copiar um arquivo de um diretório para outro, queremos ter certeza que não estamos sobrescrevendo o novo pelo antigo. Para saber isto temos que comparar as datas do arquivo de origem com o destino.

Vamos ver uma classe que faz esta comparação.


import java.util.*;
import java.io.File;


/**
* compara a data de dois arquivos
* @param arg[0] arquivo de origem
* @param arg[1] arquivo de destino
*/
public class ComparaDatasArquivos {
  public static void main(String[] args) { 
    if (args.length < 2) {
      System.out.println("Uso: java ComparaDatasArquivos arquivo1 arquivo2");
      System.exit(0);
    }


    // pega os dois arquivos
    File f1 = new File(args[0]); 
    File f2 = new File(args[1]); 


    if (!(f1.exists() && f2.exists())) {
      System.out.println("Arquivo inexistente! Operação cancelada");
      System.exit(0);
    }


    // pega as datas dos arquivos
    long d1 = f1.lastModified();
    long d2 = f2.lastModified(); 
    String situacao;
    if (d1 == d2)
      situacao = "tem mesma data que";
    else if (d1 < d2)
      situacao = "eh mais antigo que";
    else
      situacao = "eh mais novo que";
    System.out.println(f1.getName() + " " + situacao + " " + f2.getName());
  }
}


Compilem e rodem

PS: Notem a construção do if .. else if .. else do final da classe. Quando se tem um comando, não é necessário criar um bloco com { }

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: