Como utilizar o mecanismo de serialização de objetos para representar o estado de um objeto como uma sequência de bytes. Com a serialização é possível salvar objetos em arquivos de dados. Já a desserialização permite que os objetos persistidos em arquivos possam ser recuperados e seus valores recriados na memória.

O processo de serialização de objetos é bastante utilizado em sistemas distribuídos (coleção de computadores independentes conectados por uma rede e equipados com um sistema de software distribuído) e na persistência de dados (manter dados além da duração da execução do programa). Com a transformação do objeto em bytes é possível enviar o objeto por uma rede, ou salvá-lo em um arquivo ou em um banco de dados.

O que é Serialização de Objetos?

Serialização é a técnica que permite transformar o estado de um objeto em uma sequência bytes. Depois que um objeto for serializado ele pode ser gravado (ou persistido) em um arquivo de dados e recuperado do arquivo e desserializado para recriar o objeto na memória.

A orientação a objetos surgiu na década de 60, através da linguagem de programação Simula 67, adequada à programação de simulações de sistemas que podem ser modelados pela interação de um grande número de objetos distintos. Uma classe em Simula é um módulo englobando a definição da estrutura e do comportamento comuns a todas as suas instâncias (objetos).

As ideias implementadas na linguagem Simula serviram de base para a linguagem Smalltalk, desenvolvida no Centro de Pesquisas da Xerox durante a década de 70, que incorporou o princípio de objetos ativos, prontos a reagir a mensagens que ativam comportamentos específicos do objeto.

Os conceitos introduzidos pelas linguagens Simula e Smalltalk ganharam evidência na década de 90, a partir de modelos orientados a objetos sugeridos por diversos autores como Booch, Rumbaugh e Jacobson, com o propósito de ajudar a diminuir a complexidade do desenvolvimento de software.

Os fundamentos do modelo de objetos, apresentados na Figura 1, aplicados ao processo de desenvolvimento de software complexo dividem-se em três etapas: 1) Análise Orientada a Objetos que se preocupa em enxergar a estrutura do problema e decompô-la em entidades “abstratas” de classes e objetos; 2) Projeto Orientado a Objetos que procura organizar e descrever essa estrutura “sistematicamente” em um modelo de objetos; e, 3) Programação Orientada a Objetos que “implementa” as estruturas modeladas em código de computador.

Fundamentos do
modelo de objetos
Figura 1. Fundamentos do modelo de objetos.

Elementos chave da programação orientada a objetos: classe e objeto

Java é uma linguagem orientada a objetos. O desenvolvimento de software baseado no modelo da orientação a objetos permite aos programadores de computador construir sistemas a partir de componentes reutilizáveis, chamados de classes. Uma classe generaliza/representa um conjunto de objetos similares que interagem entre si para atingir o resultado esperado.

A classe é uma abstração (modelo conceitual) que descreve as propriedades relevantes de uma aplicação em termos de sua estrutura (dados) e de seu comportamento (operações). Em programação a classe corresponde a um tipo de dados definido pelo usuário que tem alguns dados internos (atributos) e algumas operações (métodos), na forma de procedimentos ou funções, que atuam sobre estes dados. Resumindo, a classe é uma entidade abstrata (tipo de dados), um gabarito usado na declaração e criação de objetos. Através da definição de uma classe, descreve-se que atributos, ou propriedades o objeto terá e que funcionalidades podem ser requisitadas aos objetos da classe.

No paradigma de orientação a objetos, tudo pode ser potencialmente representado como um objeto. Sob o ponto de vista da programação, um objeto não é muito diferente de uma variável no paradigma de programação convencional. Por exemplo, quando define-se uma variável do tipo int em Java, essa variável tem: a) um espaço em memória para registrar o seu estado atual (um valor); e, b) um conjunto de operações associadas que podem ser aplicadas a ela, através dos operadores definidos na linguagem que podem ser aplicados a valores inteiros (soma, subtração, multiplicação e divisão, por exemplo). Da mesma forma, quando cria-se um objeto, esse objeto adquire um espaço em memória para armazenar seu estado (os valores de seu conjunto de atributos, definidos pela classe) e um conjunto de operações que podem ser aplicadas ao objeto (o conjunto de métodos definidos pela classe). Resumindo, os objetos são entidades reais (variáveis), existem no tempo, são mutáveis, têm estado e comportamento, e podem ser criados e destruídos.

O dispositivo de memória principal de um computador é volátil, não permitindo que as informações fiquem armazenadas permanentemente. Por este motivo os dados armazenados em variáveis e, portanto, o estado de um objeto é perdido sempre que um programa terminar sua execução normalmente ou devido a algum problema. A solução para este tipo de situação é utilizar uma estrutura de dados que permita a gravação de informações em dispositivos de memória secundária como disquete, disco rígido, entre outros. Nas linguagens de programação, a estrutura de dados que guarda informações em dispositivos de armazenamento secundário é chamada de arquivo.

Um objeto serializado é um objeto representado como uma sequência de bytes que inclui os dados do objeto bem como as informações sobre o tipo do objeto e os tipos dos dados armazenados no objeto. Uma vez serializado o objeto pode ser salvo em arquivos ou transmitido remotamente usando uma rede de computadores através de um fluxo de dados ou stream via HTTP, via socket, entre outros.

Neste artigo, será abordado apenas como os programas Java gravam em um arquivo os objetos serializados e como eles são recuperados do arquivo e desserializados, isto é, como as informações dos tipos e bytes que representam o objeto e seus dados podem ser utilizadas para recriar o objeto na memória.

Definindo uma estrutura para as informações da aplicação: classe Pessoa

O Java não impõe nenhuma estrutura a um arquivo. Noções de registro, por exemplo, não fazem parte da linguagem Java. Neste caso, o programador deve estruturar as informações nos arquivos de modo que eles atendam os requisitos de dados da aplicação pretendida.

A classe Pessoa, apresentada na Listagem 1, será empregada para estabelecer uma estrutura de registro para um arquivo utilizado para manter informações de um conjunto de pessoas adotado em um sistema para controle do Índice de Massa Corpórea (IMC). A estrutura da referida classe possui os seguintes atributos e métodos:

  • String nome – atributo nome da pessoa;
  • double pc – atributo peso corporal da pessoa (valor em quilogramas);
  • double alt – atributo altura da pessoa (valor em metros);
  • Pessoa(String nome, double pc, double alt) – método construtor da classe;
  • String getNome() – método que permite o acesso ao atributo nome;
  • String setNome() – método que modifica o valor do atributo nome;
  • String getPC() – método que permite o acesso ao atributo pc;
  • String setPC() – método que modifica o valor do atributo pc;
  • String getAlt() – método que permite o acesso ao atributo alt;
  • String setAlt() – método que modifica o valor do atributo alt;
  • double IMC() – método que retorna o cálculo do IMC que é definido pela relação entre peso corporal dividido pelo quadrado da altura da pessoa. O IMC é uma medida utilizada para medir a obesidade adotada pela Organização Mundial de Saúde. É o padrão internacional para avaliar o grau de obesidade de um indivíduo;
  • String interpretaIMC() – método que retorna a interpretação do valor do IMC calculado através da classificação fornecida pelo Sistema de Vigilância Alimentar e Nutricional (SISVAN), levando em consideração indivíduos adultos.

Listagem 1. Classe Pessoa mantém informações de um indivíduo.

import java.io.Serializable;
   
  public class Pessoa implements Serializable {
    private String nome;
    private double pc;   // peso corporal
    private double alt;  // altura em metros
   
    public Pessoa(String nome, double pc, double alt) {
      this.nome = nome;
      this.pc = pc;
      this.alt = alt;
    }
   
    public String getNome() {
      return nome;
    }
   
    public void setNome(String nome) {
      this.nome = nome;
    }
   
    public double getPC() {
      return pc;
    }
   
    public void setPC(float pc) {
      this.pc = pc;
    }
   
    public double getAlt() {
      return alt;
    }
   
    public void setAlt(float alt) {
      this.alt = alt;
    }
   
    public double IMC() {
      return(getPC() / (getAlt() * getAlt()));
    }
   
    public String interpretaIMC() {
      double vlrIMC = IMC();
      if (vlrIMC < 18.5)
         return("baixo peso");
      else if (vlrIMC < 25.0)
              return("peso adequado");
           else if (vlrIMC < 30.0)
                   return("sobrepeso");
                else return("obesidade");
    }
  }

Para criar automaticamente no NetBeans os métodos que permitem o acesso (get) e a modificação (set) dos valores dos atributos privados da classe, deve-se proceder da seguinte forma:

1) com o mouse, selecionar os atributos;

2) na barra de menu, selecionar a opção: Refatorar | Encapsular Campos...;

3) na janela Encapsular Campos: selecionar os campos e pressionar o botão Refatorar.

Um aspecto importante que deve ser observado, ainda na Listagem 1, é que toda classe para permitir que seus objetos tenham a capacidade de serem serializados, deve “obrigatoriamente” implementar a interface java.io.Serializable. Essa interface não possui nenhum método. Ela é usada apenas para registrar a semântica de serialização para a máquina virtual Java, indicando que os objetos instanciados a partir da classe podem ser serializados (ou transformados em uma sequência de bytes).

Serializando e desserializando objetos: classe Empacotamento

O processo de serialização de objetos com o propósito de persisti-los em arquivos de dados passa por três etapas:

a) Estruturar as informações do objeto em uma classe que implementa a interface Serializable: classe Pessoa na Listagem 1;

b) Persistir os objetos serializados em um arquivo binário: método gravarArquivoBinario() da classe Empacotamento na Listagem 2;

c) Recuperar os objetos serializados do arquivo binário: método lerArquivoBinario() da classe Empacotamento na Listagem 2.

Programas Java implementam o processamento de arquivos e a serialização de objetos utilizando as classes do pacote java.io. As classes ObjectOutputStream e ObjectInputStream permitem que objetos inteiros sejam gravados em ou lidos de um fluxo de dados, por exemplo. Para utilizar a serialização com arquivos, estas classes devem ser inicializadas com objetos de fluxo que gravam em ou leem de arquivos os objetos das classes FileOutputStream e FileInputStream, respectivamente.

A Listagem 2 apresenta uma forma de utilizar a classe ObjectOutputStream na serialização de objetos em arquivo binário e a classe ObjectInputStream na desserialização dos objetos persistidos no arquivo binário.

Listagem 2. Classe Empacotamento permite serializar e desserializar objetos.

import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
   
  public class Empacotamento {
   
    // serialização: gravando o objetos no arquivo binário "nomeArq"
    public static void gravarArquivoBinario(ArrayList<Object> lista, String nomeArq) {
      File arq = new File(nomeArq);
      try {
        arq.delete();
        arq.createNewFile();
   
        ObjectOutputStream objOutput = new ObjectOutputStream(new FileOutputStream(arq));
        objOutput.writeObject(lista);
        objOutput.close();
   
      } catch(IOException erro) {
          System.out.printf("Erro: %s", erro.getMessage());
      }
    }
   
    // desserialização: recuperando os objetos gravados no arquivo binário "nomeArq"
    public static ArrayList<Object> lerArquivoBinario(String nomeArq) {
      ArrayList<Object> lista = new ArrayList();
      try {
        File arq = new File(nomeArq);
        if (arq.exists()) {
           ObjectInputStream objInput = new ObjectInputStream(new FileInputStream(arq));
           lista = (ArrayList<Object>)objInput.readObject();
           objInput.close();
        }
      } catch(IOException erro1) {
          System.out.printf("Erro: %s", erro1.getMessage());
      } catch(ClassNotFoundException erro2) {
          System.out.printf("Erro: %s", erro2.getMessage());
      }
   
      return(lista);
    }
   
  }

No código fonte da Listagem 2, o método gravarArquivoBinario() realiza o processo de serialização, transformar o estado de um objeto em memória para uma sequência de bytes, gravando no arquivo binário indicado pelo parâmetro nomeArq todos os objetos do ArrayList lista. Primeiramente, o arquivo externo é aberto para operações de saída através do objeto arq instanciado e criado a partir da classe File. Em seguida, o objeto de gravação objOutput é associado a um fluxo de saída de dados baseado em bytes através da classe ObjectOutputStream. A classe FileOutputStream fornece métodos para gravar arrays de bytes, no entanto, deseja-se gravar objetos serializados no arquivo, uma capacidade não fornecida por esta classe usada para saídas baseadas em bytes. Por essa razão, deve-se empacotar na instrução para criação do objeto objOutput, passando um novo objeto FileOutputStream para o construtor da classe ObjectOutputStream. Finalmente, o método writeObject() serializa e transfere “todos” os objetos armazenados no parâmetro lista para o arquivo binário, que é fechado através do método close().

Relacionado

  • Java: Por onde começar?:
    Neste DevCast conversamos sobre o primeiro contato do programador com o Java. JRE, JDK, Java SE? E a orientação a objetos? Qual caminho seguir? O que devo aprender para começar a programar em Java? Simples, dê o play e confira! :)
  • Preparando o ambiente para programar em Java:
    Neste curso você aprenderá a preparar seu ambiente para programar em Java. Veremos aqui o que é necessário instalar e como proceder para desenvolver aplicações com essa linguagem.
  • Variáveis e constantes no Java:
    Neste documento será apresentado como declarar e utilizar variáveis e constantes no Java. É por meio delas que conseguimos guardar os dados em memória e acessá-los quando necessário.

Ainda no código fonte apresentado na Listagem 2, pode-se observar o método lerArquivoBinario() implementado para realizar o processo de desserialização, dados de um objeto são utilizados para recriar o objeto na memória, recuperando os objetos serializados e persistidos no arquivo binário indicado pelo parâmetro nomeArq. Primeiramente, o arquivo externo é aberto para operações de entrada através do objeto arq instanciado e criado a partir da classe File. Em seguida, o objeto de leitura objInput é associado a um fluxo de entrada de dados baseado em bytes através da classe ObjectInputStream. Os bytes que representam os objetos no arquivo foram gravados através de um objeto ObjectOutputStrem e, portanto, devem ser lidos do arquivo no mesmo formato de gravação. Desta forma, deve-se empacotar na instrução para criação do objeto objInput, passando um novo objeto FiileInputStream para o construtor da classe ObjectInputStream. Finalmente, o método readObject() desserializa e recupera “todos” os objetos gravados no arquivo binário, armazenando o estado dos objetos recriados na memória na variável lista que é retornada como resultado da execução do método. O fluxo de entrada é fechado através do método close().

Outro aspecto importante presente na implementação dos métodos gravarArquivoBinario() e lerArquivoBinario(), novamente apresentados na Listagem 2, refere-se a utilização da classe java.lang.Object, que representa a superclasse de toda a hierarquia de classes Java. Esta estratégia de desenvolvimento faz com que os referidos métodos possam ser aplicados na serialização e desserialização de qualquer tipo de objeto, uma vez que Object é a classe “raiz” da hierarquia, a partir da qual todas as classes são definidas (ou derivadas).

Criando um arquivo binário com a serialização dos objetos

A partir desta seção será demonstrada a utilização da classe Pessoa (Listagem 1), responsável pela estruturação das informações do arquivo; e da classe Empacotamento (Listagem 2), desenvolvida para permitir a serialização e desserialização de objetos, com propósito de persistir em arquivos binários o estado dos objetos criados por aplicações Java.

Primeiramente será apresentada a gravação de dados (ou objetos) em um arquivo binário. Os fluxos de entrada e saída baseados em bytes, denominados de arquivos binários, armazenam e recuperam dados no formato binário como uma sequência de bytes.

Na Listagem 3 tem-se uma aplicação Java que persiste os objetos criados em um fluxo de saída baseado em bytes implementando três etapas: 1) desserialização: recuperando os dados gravados no arquivo binário e recriando o estado dos objetos na memória; 2) realizando o processo de entrada de dados; e, 3) serialização: transformando o estado dos objetos em uma sequência de bytes e gravando o resultado em um arquivo binário.

Listagem 3. Entrada de dados e serialização dos objetos no arquivo dados.dat.

import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Scanner;
   
  public class Exemplo1 {
   
    public static void main(String[] args) throws IOException {
      Scanner ler = new Scanner(System.in);
   
      String nome;
      double pc;
      double alt;
   
      // 1) desserialização: recuperando os objetos gravados no arquivo binário "dados.dat"
      ArrayList<Object> pessoa = Empacotamento.lerArquivoBinario("dados.dat");
   
      // 2) entrada de dados
      while (true) {
        System.out.printf("Ficha nro: %d.\n", (pessoa.size()+1));
        System.out.printf("Informe o nome da pessoa, FIM para encerrar:\n");
        nome = ler.nextLine();
        if (nome.equalsIgnoreCase("FIM"))
           break;
   
        System.out.printf("\nInforme o peso corporal (em kg)...............: ");
        pc = ler.nextDouble();
   
        System.out.printf("Informe a altura (em metros: 1,77 por exemplo): ");
        alt = ler.nextDouble();
   
        pessoa.add(new Pessoa(nome, pc, alt)); // adiciona um novo objeto a lista
   
        ler.nextLine(); // esvazia o buffer do teclado
        System.out.printf("\n");
      }
   
      // 3) serialização: gravando o objeto no arquivo binário "dados.dat"
      Empacotamento.gravarArquivoBinario(pessoa, "dados.dat");
    }
   
  }

Na aplicação Java, apresentada na Listagem 3, foi utilizado o método lerArquivoBinário() da classe Empacotamento (Listagem 2) para recuperar os objetos gravados no arquivo binário dados.dat. Os objetos recriados na memória serão armazenados na lista pessoa. A seguir foi implementado o processo de entrada dos dados: nome, peso corporal e altura, usando os métodos da classe Scanner. A cada entrada de dados um novo objeto pessoa é adicionado na lista. Encerrado o processo de entrada de dados os objetos são persistidos no arquivo binário dados.dat através da execução do método gravarArquivoBinario() da classe Empacotamento (Listagem 2). A Figura 2 ilustra a execução da classe Exemplo1 no processo de entrada de dados.

Executando a
classe Exemplo1 na entrada de dados
Figura 2. Executando a classe Exemplo1 na entrada de dados.

Lendo e desserializando dados a partir do arquivo binário

Para Deitel & Deitel os dados são armazenados em arquivos de forma que possam ser recuperados para processamento quando necessários. Nesta seção, através do código fonte apresentado na Listagem 4, será demonstrada a recuperação dos objetos serializados e gravados em um arquivo binário.

Listagem 4. Lendo dados do arquivo binário dados.dat (desserialização dos objetos persistidos).

import java.util.ArrayList;
   
  public class Exemplo2 {
   
    public static void main(String[] args) {
      // desserialização: recuperando os objetos gravados no arquivo binário "dados.dat"
      ArrayList<Object> pessoa = Empacotamento.lerArquivoBinario("dados.dat");
   
      int i = 1;
      for (Object item: pessoa) {
        System.out.printf("Ficha nro....: %d.\n", i++);
        // ((Pessoa)item) - implementa o mecanismo de downcast, ou seja,
        //                  o objeto "item" declarado a partir da classe
        //                  base "Object" é referenciado como um objeto "Pessoa"
        System.out.printf("Nome.........: %s\n", ((Pessoa)item).getNome());
        System.out.printf("Peso Corporal: %.2f kgs\n", ((Pessoa)item).getPC());
        System.out.printf("Altura.......: %.2f metros\n", ((Pessoa)item).getAlt());
        System.out.printf("IMC..........: %.2f\n", ((Pessoa)item).IMC());
        System.out.printf("Interpretacao: %s\n\n", ((Pessoa)item).interpretaIMC());
      }
    }
   
  }

Na aplicação Java, apresentada na Listagem 4, foi utilizado o método lerArquivoBinário() da classe Empacotamento (Listagem 2) para recuperar os objetos gravados no arquivo binário dados.dat. Os objetos recriados na memória serão armazenados na lista pessoa. A seguir foi utilizada uma estrutura “for” aprimorada para percorrer os elementos (ou objetos) da lista mostrando os dados: número da ficha, nome da pessoa, peso corporal, altura, IMC calculado e a interpretação do IMC calculado. Usando este tipo de estrutura de repetição não é necessário declarar um contador para indexar os elementos da lista. O tipo usado, no caso, a classe Object, representa os valores sucessivos da lista nas sucessivas iterações da instrução “for”. A lista pessoa e também o identificador item foram declarados usando a superclasse Object, e para que o item tenha acesso às funcionalidades completas da classe Pessoa (Listagem 1) deve-se fazer uso do mecanismo de downcast através da declaração ((Pessoa)item). A Figura 3 ilustra a execução da classe Exemplo2 na recuperação dos objetos persistidos no arquivo binário.

Executando a
classe Exemplo2 na desserialização dos objetos
persistidos
Figura 3. Executando a classe Exemplo2 na desserialização dos objetos persistidos.

Exportação de dados

Os computadores utilizam os arquivos como estruturas de dados para armazenamento de longo prazo de grandes volumes de dados. Dados dos objetos manipulados em uma aplicação e mantidos em arquivos são chamados de dados persistentes porque eles existem além da duração da execução do programa em dispositivos de armazenamento secundário.

A exportação de dados persistidos corresponde à tarefa de compartilhar a mesma fonte de dados entre diversos aplicativos que podem, por exemplo, ser implementados em ambientes de desenvolvimento de naturezas diferentes. Uma aplicação para exportar dados deve criar um arquivo em um formato que outro aplicativo entende, permitindo assim que os dois programas possam compartilhar os mesmos dados. Em geral, dados exportados se apresentam no formato texto uma vez que arquivos que utilizam este formato podem ser facilmente lidos ou abertos por qualquer programa que lê texto e, por essa razão, são considerados universais.

A Listagem 5 apresenta como utilizar as classes FileWriter e PrinterWriter na criação e gravação, através do método printf(), de dados baseada em caracteres para um arquivo de texto de exportação.

Listagem 5. Exportando para TXT os dados dos objetos persistidos no arquivo binário dados.dat.

import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.ArrayList;
   
  public class Exportacao {
   
    public static void main(String[] args) throws IOException {
      // desserialização: recuperando os objetos gravados no arquivo binário "dados.dat"
      ArrayList<Object> pessoa = Empacotamento.lerArquivoBinario("dados.dat");
   
      FileWriter arq = new FileWriter("export.txt");
      PrintWriter gravarArq = new PrintWriter(arq);
   
      int i = 1;
      int n = pessoa.size();
   
      for (Object item: pessoa) {
        System.out.printf("Exportando %do. registro de %d: %s\n",
          i++, n, ((Pessoa)item).getNome());
          
        gravarArq.printf("Nome|%s;Peso Corporal|%.2f;Altura|%.2f;IMC|%.2f;Interpretação|%s%n",
          ((Pessoa)item).getNome(),
          ((Pessoa)item).getPC(),
          ((Pessoa)item).getAlt(),
          ((Pessoa)item).IMC(),
          ((Pessoa)item).interpretaIMC());
      }
   
      gravarArq.close();
   
      System.out.printf("\nExportação realizada com sucesso.\n");
    }
   
  }

Na aplicação Java, apresentada na Listagem 5, foi utilizado o método lerArquivoBinário() da classe Empacotamento (Listagem 2) para recuperar os objetos gravados no arquivo binário dados.dat. Os objetos recriados na memória serão armazenados na lista pessoa. A seguir o arquivo externo export.txt é aberto para operações de saída através do objeto arq instanciado e criado a partir da classe FileWriter. Já o objeto de gravação gravarArq é associado a um fluxo de saída de dados baseado em caracteres através da classe PrinterWriter. Definido o arquivo de texto externo, foi implementado o processo de repetição (for) para percorrer os elementos (ou objetos) da lista recuperando os dados: nome da pessoa, peso corporal, altura, IMC calculado e a interpretação do IMC calculado, que serão gravados no arquivo texto de saída através do método printf(). Para organizar e separar as informações gravadas no arquivo texto de exportação foram utilizados os caracteres “|” e “;”. O caractere “|” foi utilizado para indicar o nome do campo de dados, enquanto que o caractere “;” indica o fim da informação do campo gravado. Ao final do processo o arquivo é fechado através do método close().

A Figura 4 apresenta a execução da classe Exportacao na criação do arquivo de texto de exportação export.txt, enquanto que a Figura 5 mostra o resultado da gravação através do arquivo aberto pelo bloco de notas.

Executando a
classe Exportacao para exportar os dados da aplicação
para TXT
Figura 4. Executando a classe Exportacao para exportar os dados da aplicação para TXT.
Arquivo TXT de
exportação aberto no bloco de notas
Figura 5. Arquivo TXT de exportação aberto no bloco de notas.

Importação de dados

Para utilizar os dados produzidos, durante o processo de exportação por outro aplicativo, o programa de importação deve implementar a capacidade de recuperar e processar os dados importados. Uma aplicação para importar dados deve ser capaz de reconhecer o formato e a organização dos dados criados no arquivo texto de exportação.

Na Listagem 6 foram utilizadas as classes FileReader e BufferedReader na abertura e leitura de dados, através do método readLine(), de um arquivo de texto de importação.

Listagem 6. Importando de TXT os dados dos objetos exportados.

import java.io.BufferedReader;
  import java.io.FileNotFoundException;
  import java.io.FileReader;
  import java.io.IOException;
   
  public class Importacao {
   
    public static void main(String[] args) throws FileNotFoundException, IOException {
      FileReader arq = new FileReader("export.txt");
      BufferedReader lerArq = new BufferedReader(arq);
   
      int i = 1, j, n;
   
      String linha = lerArq.readLine();
      while (linha != null) {
        System.out.printf("Fichar nro: %d.\n", i);
   
        n = linha.length();
        for (j=0; j<n; j++) {
          if (linha.charAt(j) == '|')
             System.out.printf(": ");
          else if (linha.charAt(j) == ';')
                  System.out.printf("\n");
               else System.out.printf("%c", linha.charAt(j));
        }
   
        System.out.printf("\n\n");
   
        i++;
        linha = lerArq.readLine();
      }
   
      lerArq.close();
    }
   
  }

Na aplicação Java da Listagem 6 o arquivo texto de importação export.txt será aberto para operações de entrada através do objeto arq, instanciado e criado a partir da classe FileReader. Já o objeto de leitura lerArq é associado a um fluxo de entrada de dados baseado em carecteres através da classe BufferedReader. Definido o arquivo de texto externo, foi implementado um processo de repetição (while) para ler todas as linhas do arquivo e exibi-las no fluxo padrão de saída System.out. O processo de repetição (for) percorre os caracteres da linha separando as informações recuperadas, sendo que o caractere “|” indica o final do nome do campo de dados e o caractere “;” indica o fim da informação do campo recuperado. Ao final do processo o arquivo é fechado através do método close(). A Figura 6 ilustra a execução da classe Importacao na recuperação dos dados exportados.

Executando a
classe Importacao na recuperação de dados exportados
no TXT
Figura 6. Executando a classe Importacao na recuperação de dados exportados no TXT.

Conclusões

Neste artigo foi apresentado como as aplicações Java gravam em um arquivo os objetos serializados e como eles são recuperados do arquivo e desserializados.

Os computadores utilizam os arquivos como estruturas de dados para armazenar (ou persistir) na memória secundária de um sistema, usualmente unidades de disco rígido, grandes volumes de dados.

O mecanismo de serialização de objetos permite converter a representação interna de um objeto para uma sequência de bytes. Uma vez serializado, um objeto pode ser salvo em arquivo e recuperado a partir do arquivo e desserializado para recriar o objeto na memória.

O processo de serialização de objetos com o propósito de persisti-los em arquivos de dados passa por três etapas: 1) estruturar as informações do objeto em uma classe que implementa a interface Serializable; 2) persistir os objetos serializados em um arquivo binário; e, 3) recuperar os objetos serializados do arquivo binário.

Programas Java implementam a manipulação de arquivos de dados e a serialização de objetos utilizando as classes do pacote java.io. A serialização de objetos é viabilizada através da utilização das classes ObjectOutputStream e FileOutputStream, que empacotadas na criação de objetos de gravação, permitem que um conjunto de objetos possam ser serializados e gravados em um fluxo de dados baseado em bytes, por exemplo. Para permitir a desserialização são usadas as classes ObjectInputStream e FileInputStream, que possibilitam a criação de objetos de leitura para recuperar do fluxo de dados os objetos.

Links Úteis

  • Um Bate-papo sobre Angular:
    Angular é um framework para criação de aplicações cliente baseadas em HTML, que serão executadas no navegador ou em dispositivos móveis, recebendo dados através da internet. Ficou curioso? Então saiba mais sobre o Angular neste DevCast.
  • Segurança de web services em Java com controle de acesso:
    Neste curso vamos aprender a programar um mecanismo de autorização para controle de acesso às diferentes funcionalidades oferecidas por uma Web API RESTful, configurando para três tipos de usuário (cliente, funcionário e administrador) diferentes tipos de permissão.
  • O que é Yarn?:
    Neste curso aprenderemos o que é o Yarn: um gerenciador de dependências concorrente do NPM que promete ser mais rápido e eficiente que este. Por meio do Yarn é possível instalar os mesmos pacotes do NPM e do Bower, de forma rápida e inclusive offline.

Saiba mais sobre Java ;)

  • Java: operadores de atribuição, aritméticos, relacionais e lógicos:
    Este documento apresenta os operadores aritméticos e os operadores relacionais/lógicos, utilizados para a escrita de algoritmos em Java, principalmente operações matemáticas e condições booleanas.
  • Carreira Programador Java:
    Aprender Java não é uma tarefa simples, mas seguindo a ordem proposta nesse Guia, você evitará muitas confusões e perdas de tempo no seu aprendizado. Vem aprender java de verdade, vem!
  • if/else e o operador ternário no Java:
    Este documento apresenta as estruturas condicionais if/else e operador ternário, recursos que possibilitam executar diferentes trechos de código com base em uma expressão booleana.
Referências

Deitel, H.M. (2005) Java: como programar. São Paulo: Person Prentice Hall, 6ª edição. Capítulo 14: Arquivos e fluxos, páginas 494-550.

Links: