sexta-feira, 23 de dezembro de 2011

Acesso a arquivo - Parte II

Vamos ver como funciona a classe StringTokenizer utilizada no programa na parte I deste post. Esta classe permite que você separe palavras (tokens) em qualquer formato. Por exemplo, nos registros armazenados cada campo estava separado por um ”;”.

Esta classe está disponível em java.util.StringTokenizer. Possui três construtores:
  • StringTokenizer(String str)
  • StringTokenizer(String str, String delim)
  • StringTokenizer(String str, String delim, boolean returnDelims)
onde:
str - é a string que desejamos vasculhar
delim - indica o delimitador que iremos procurar, por exemplo ";"
returnDelims - uma flag que indice se os delimitadores devem ser retornados como tokens. Nos dois primeiros construtores, onde esta flag não é indicada, os delimitadores NÃO são tratados como tokens.


Os métodos que utilizamos foram:
  • countTokens() - indica quantos elementos foram separados
  • hasMoreTokens() - retorna true se ainda existem elementos na lista para serem recuperados com nextToken
  • nextToken() - retorna o próximo token. Notem que foi este método que nos permitiu recuperar os campos do registro do arquivo texto.

quinta-feira, 22 de dezembro de 2011

Acesso a arquivo - Parte I


Vamos supor que desejamos fazer um programa para ler um log de registro de ponto de um coletor simples. As informações do registro de ponto que são gravadas no arquivo texto são:

  • número do crachá,
  • data e hora do registro,
  • número do relógio,
  • indicação do método de registro (crachá, teclado, biometria, biometria + crachá ou biometria + teclado),
  • número da função selecionada pelo colaborador,
  • indicação do registro efetuado pelo mestre,
  • indicação do registro efetuado pelo teclado,
  • sentido de passagem (entrada ou saída), 
  • data e hora da coleta do registro.

Utilizaremos um arquivo de exemplo contendo as seguintes linhas:

A classe que lê um arquivo de strings e que os registros está descrita abaixo:



import java.io.*;
import java.util.*;
import java.util.ArrayList;


 /*
  campos do arquivo de batidas do relógio:
   1) número do crachá
   2) data
   3) hora do registro
   4) número do relógio
   5) indicação do método de registro (crachá, teclado, biometria, biometria + crachá ou biometria + teclado)
   6) número da função selecionada pelo colaborador
   7) indicação do registro efetuado pelo mestre
   8) indicação do registro efetuado pelo teclado
   9) sentido de passagem (entrada ou saída)
  10) data da coleta do registro
  11) hora da coleta do registro
 */
public class ExemploArquivo1 {
 String nomeArquivo; // guarda o nome do arquivo CSV


 public ExemploArquivo1(String nom) {
   nomeArquivo = nom;
 }


 // carrega o arquivo para memória, armazenando na lista
 private ArrayList<String> LeDadosCSV() {
   String linhaLida;
   ArrayList<String> lista = new ArrayList<String>();
   boolean eof = false;
   try {
     FileReader arq = new FileReader(nomeArquivo);
     BufferedReader buf = new BufferedReader(arq);
     while (!eof) {
       linhaLida = buf.readLine();
       if (linhaLida == null) {
         eof = true;
       }
       else {
         lista.add(linhaLida);
       }
     }
     buf.close();
     arq.close();
   } catch (IOException e) {
     System.out.println("Erro de acesso a arquivo ["+nomeArquivo+"] " + e.toString());
   }
   return lista; // retorna em lista o arquivo lido
 }


 private void ApresentaLog(String log) {
  StringTokenizer tokens = new StringTokenizer(log, ";");
  String[] campos = new String[11]; // são 11 campos
  // preenche os campos
  for(int i=0;tokens.hasMoreTokens();i++) {
   campos[i] = tokens.nextToken();
  }
  System.out.println("cracha : " + campos[0]);
  System.out.println(" registro["+campos[8]+"] : " + campos[1] + " " + campos[2]);
 }


 public static void main(String[] args) {
  // verifica se foi passado o parâmetro com o nome do arquivo
  if (args.length < 1) {
   System.out.println("Uso: java ExemploArquivoLe arquivo.cvs");
   System.exit(0);  
  }


  // verifica se o arquivo existe
  if (!(new File(args[0])).exists()) {
   System.out.println("Arquivo ["+args[0]+"] não encontrado!");
   System.exit(0);  
  }


  // chama a classe para processamento
  ExemploArquivo1 batidas = new ExemploArquivo1(args[0]);
  ArrayList<String> logs = batidas.LeDadosCSV();
  for(String s : logs) {
    batidas.ApresentaLog(s);
  }
 }
}


Para a leitura do arquivo de logs utilizamos duas classes : FileReader e BufferedReader

A classe FileReader está em java.io e sua função é permitir a leitura de arquivos de caracteres. Esta classe assume a codificação de caracteres default e utiliza um tamanho de buffer também default. Isto é suficiente para nós neste exemplo. Caso fosse necessário alterar algum destes parâmetros, deveríamos utilizar InputStreamReader ou FileInputStream.

Esta classe possuir 3 construtores:
  • FileReader(File arquivo)
  • FileReader(String nomeDoArquivo)
  • FileReader(FileDescriptor arqDesc)
Note que utilizamos o 2º formato. Veja que utilizamos no método main() a construção new File(args[0])).exists() para testar se o arquivo existe. Poderíamos ter gerado uma variação da classe com as seguintes alterações (note que retirei as linhas da classe original que permaneceram sem alteração):

public class ExemploArquivo2 {
 static File arquivo;
 
 public ExemploArquivo2(File arq) {
   arquivo = arq;
 }

 // carrega o arquivo para memória, armazenando na lista
 private ArrayList<String> LeDadosCSV() {
     ...
     FileReader arq = new FileReader(arquivo);
     ...
     System.out.println("Erro de acesso a arquivo ["+arquivo.getName()+"] " + e.toString());
 }

 public static void main(String[] args) {
     ...
  arquivo = new File(args[0]);
  if (!arquivo.exists()) {
     ...
  ExemploArquivo2 batidas = new ExemploArquivo2(arquivo);
 }
}

A classe FileReader é utilizada como Reader. Para ler as linhas utilizamos uma segunda classe denominada BufferedReader. O construtor tem o formato BufferedReader(Reader arquivo). Esta classe tem um método muito interessante para nós que é BufferedReader.readLine(). Este método retorna:
  • se existir a linha no arquivo: uma string contendo o conteúdo , sem os terminadores de linha
  • se não existir, retorna null.
O método gera uma exceção denominada IOException e por isto temos que colocar o try...catch.

Em uma nova postagem, continuo a comentar o funcionamento...

sexta-feira, 16 de dezembro de 2011

Vector


A classe denominada java.util.Vector implementa um array de objetos que pode ter a quantidade de elementos alterada - itens podem ser inseridos ou apagados depois da criação do objeto Vector. Da mesma forma que um Array, os elementos podem ser acessados via um índice inteiro.

Esta classe permite o uso de iterators para acessar os seus componentes. Um iterator depois de criado, ao tentar ler um objeto que foi removido ou adicionado por outro processo depois do iterator ter sido criado, gera uma exceção ConcurrentModificationException. Este comportamento é denominado fail-fast. Uma boa programação não utiliza esta característica, já que a exceção é gerada como best effort. Esta classe retorna também Enumerations, porém este não são fail-fast.

A declaração desta classe é

public class Vector<E> extends AbstractList<E>
 implements List<E>, RandomAccess, Cloneable, Serializable

Depois de criado podemos utilizar dois métodos para inserir um objeto no Vector: .add(objeto) ou .add(indice, objeto). Veja no exemplo estas duas situações. size() retorna o número de elementos do Vector.

Vamos ver um exemplo de utilização do Vector criando um array de String que pode ser redimensionado. Notem que poderia ser qualquer tipo de objeto.

import java.util.*;
import java.util.Vector;

public class ExemploVector {
  public static void main(String[] args) {

    Vector<String> v1=new Vector<String>();
    Vector<String> v2=new Vector<String>();

    // não temos que criar a quantidade de elementos
// eles podem ser adicionados um a um, utilizando .add
    v1.add("String 1");
    v1.add("String 2");
    v1.add("String 3");
    v1.add("String 5");
    v1.add("String 6");

    // podemos adicionar um elemento em uma posição determinada
    v1.add(3, "String 4");

    // número de elementos de v1
    System.out.println("tamanho (depois dos add) :"+v1.size());

// uma forma de buscar os elementos de um Vector
Enumeration<String> vEnum = v1.elements();
System.out.println("Lista dos elementos de v1 (usando Enumerator):");
while(vEnum.hasMoreElements())
      System.out.println(vEnum.nextElement() + " ");

    // vamos copiar os seis elementos de v1 para v2
for(int i=0; i<v1.size(); i++)
     v2.add(v1.get(i));

// vamos remover os itens de indice 2 a 4
for(int i=4; i>1; i--)
      v1.remove(i);

// adiciona os itens em v2 no Vector v1
v1.addAll(v2);

// número de elementos de v1
System.out.println("tamanho (depois de adicionar v2) :"+v1.size());

// uma segunda forma de mostrar os elementos 
for(int i=0; i<v1.size(); i++) 
      System.out.println("Vector["+i+"] :"+v1.get(i));
  }
}

Esta classe compilada e executada gera o seguinte resultado: