Arquivos, Fluxos e Serialização de Objetos em Java

9
ARQUIVOS, FLUXOS e SERIALIZAÇÃO DE OBJETOS Arquivos e Persistência Programas manipulam dados armazenados em variáveis e coleções na memória principal, esses dados são perdidos quando uma variável sai do escopo ou quando o programa é encerrado. Para retenção a longo prazo (persistência) desses dados mesmo depois de os programas que os criaram encerrarem ou a máquina ser desligada, os computadores utilizam Arquivos. Esses arquivos são armazenados em dispositivos de armazenamento secundário como HD's, Flashmemo's ou CDs. Dados mantidos em arquivos são dados persistentes porque existem além da duração da execução dos programas. O Java não impõe nenhuma estrutura específica a um Arquivo, portanto os arquivos devem ser estruturados para satisfazer os requisitos do aplicativo. Os Arquivos são o reflexo da Estrutura de Dados, as informações são armazenadas em Arquivo em um formato qualquer, a forma de recuperá-las na memória pode ser como arrays, listas, filas, pilhas ou árvores. Assim, a estrutura de dado em memória não precisa ser igual aos arquivos ou às tabelas dos BD relacionais. Fluxos de Dados O processamento de arquivos é um subconjunto das capacidades de processamento de fluxos do Java, que incluem operações de I/O da memória principal, da memória secundária (Arquivos) e conexões de rede. Serialização de Objetos Dados podem ser armazenados em arquivo de texto ou arquivo binário. A tarefa de gravar e ler Objetos inteiros através de arquivos de texto é difícil, por conta disso o Java fornece maneiras de gravar e ler Objetos em Arquivos chamada Serialização e Desserialização de Objetos. Hierarquia de dados Dados são armazenados em computadores como zeros e uns e combinações desses valores são utilizadas para formar bytes, campos, Registros e Arquivos. Bits Um computador processa dados por combinações de zeros e uns, o menor item de dado que assume a forma de zero ou um é o BIT. Caracteres Programadores trabalham com letras, dígitos decimais e caracteres especiais conhecidos como char (formados por bits 0 e 1). Java utiliza caracteres Unicode UTF-8 de dois bytes que contêm caracteres para muitos idiomas. Um subconjunto popular de Unicode é o ASCII, codificação americana para letras, dígitos e caracteres especiais. Campos (Atributos) Assim como caracteres são compostos de bits, campos são compostos de caracteres char. Um campo é um grupo de caracteres (bytes) que transmite um significado.

Transcript of Arquivos, Fluxos e Serialização de Objetos em Java

Page 1: Arquivos, Fluxos e Serialização de Objetos em Java

ARQUIVOS, FLUXOS e SERIALIZAÇÃO DE OBJETOS

Arquivos e Persistência Programas manipulam dados armazenados em variáveis e coleções na memória principal, esses dados são perdidos quando uma variável sai do escopo ou quando o programa é encerrado. Para retenção a longo prazo (persistência) desses dados mesmo depois de os programas que os criaram encerrarem ou a máquina ser desligada, os computadores utilizam Arquivos. Esses arquivos são armazenados em dispositivos de armazenamento secundário como HD's, Flashmemo's ou CDs. Dados mantidos em arquivos são dados persistentes porque existem além da duração da execução dos programas. O Java não impõe nenhuma estrutura específica a um Arquivo, portanto os arquivos devem ser estruturados para satisfazer os requisitos do aplicativo. Os Arquivos são o reflexo da Estrutura de Dados, as informações são armazenadas em Arquivo em um formato qualquer, a forma de recuperá-las na memória pode ser como arrays, listas, filas, pilhas ou árvores. Assim, a estrutura de dado em memória não precisa ser igual aos arquivos ou às tabelas dos BD relacionais.

Fluxos de Dados O processamento de arquivos é um subconjunto das capacidades de processamento de fluxos do Java, que incluem operações de I/O da memória principal, da memória secundária (Arquivos) e conexões de rede.

Serialização de Objetos Dados podem ser armazenados em arquivo de texto ou arquivo binário. A tarefa de gravar e ler Objetos inteiros através de arquivos de texto é difícil, por conta disso o Java fornece maneiras de gravar e ler Objetos em Arquivos chamada Serialização e Desserialização de Objetos.

Hierarquia de dados

Dados são armazenados em computadores como zeros e uns e combinações desses valores são utilizadas

para formar bytes, campos, Registros e Arquivos.

Bits Um computador processa dados por combinações de zeros e uns, o menor item de dado que assume a forma de zero ou um é o BIT.

Caracteres Programadores trabalham com letras, dígitos decimais e caracteres especiais conhecidos como char (formados por bits 0 e 1). Java utiliza caracteres Unicode UTF-8 de dois bytes que contêm caracteres para muitos idiomas. Um subconjunto popular de Unicode é o ASCII, codificação americana para letras, dígitos e caracteres especiais.

Campos (Atributos) Assim como caracteres são compostos de bits, campos são compostos de caracteres char. Um campo é um grupo de caracteres (bytes) que transmite um significado.

Page 2: Arquivos, Fluxos e Serialização de Objetos em Java

Registros (Classes) Assim como campos são compostos de caracteres, registros são compostos por campos. Um registro é um grupo de campos relacionados e são implementados em Java por Classes.

Arquivos Assim como registros são compostos por campos, um Arquivo é composto por um grupo de Registros (classes) relacionados. Chaves de registro Para acesso a um Registro específico num Arquivo, pelo menos um Campo em cada Registro deve ser uma "chave". Uma chave de registro é única para cada registro. Arquivo Sequencial A maneira mais comum de organizar Registros num Arquivo é o Arquivo Sequencial, onde os Registros são armazenados em ordem pela Chave de Registro. Um Arquivo contém várias classes (Registros) e cada classe contém um Campo que é a Chave de Registro.

Banco de Dados Assim como um Arquivo é composto por Registros, um Banco de Dados é composto por um grupo de Arquivos relacionados. Uma coleção de programas projetados para gerenciar Bancos de Dados é chamada de SGBD ou DBMS (Data Base Management System)

Classe File A Casse File é útil para recuperar informações sobre arquivos ou diretórios em disco. Não abre nem fornece métodos de processamento de arquivos, é utilizada frequentemente com objetos de outras Classes para especificar arquivos ou diretórios a manipular. Um caminho de arquivo ou diretório (path) especifica sua localização em disco e inclui alguns ou os principais diretórios para o arquivo ou diretório.

Um "caminho absoluto" contém todos os diretórios, desde o "raiz", que levam a um arquivo ou diretório específico.

Um "caminho relativo" geralmente inicia a partir do diretório (dir) no qual o arquivo começou a executar, portanto é relativo ao diretório atual. Construtores da Classe File Com 1 argumento String - especifica nome ou diretório de um arquivo para associar com objeto File. A String pode conter o nome do arquivo ou diretório, bem como informações de caminho; Com 2 argumentos String - especifica um caminho absoluto ou relativo no 1º argumento e no 2º, o arquivo ou diretório a associar com o objeto File; Com 2 argumentos (File, String) - utiliza um objeto File existente que especifica o diretório no 1º argumento ou o diretório especificado pelo 2º argumento string; Com 1 argumento (URI) - utiliza um objeto URI - Uniform Resourse Identifier, uma forma generalizada de URL - para localizar o arquivo. Ex Windows: file://C:/data.txt

Page 3: Arquivos, Fluxos e Serialização de Objetos em Java

Métodos File comuns

boolean canRed()

true se um arquivo for legível pelo aplicativo atual

boolean canWrite()

true se um arquivo for gravável pelo aplicativo atual boolean exists()

true se o arquivo ou dir representado pelo objeto File existir boolean isFile()

true se o argumento especificado para o construtor de File é um arquivo boolean isDirectory()

true se o argumento especificado para o construtor de File é um diretório boolean isAbsolute()

true se o argumento especificado para o construtor de File indica um patch absoluto para um arquivo ou dir String isAbsolutePath()

retorna uma String com o caminho absoluto para um arquivo ou dir String getPath()

retorna uma String com o caminho para um arquivo ou dir String getName()

retorna uma String com o nome do arquivo ou dir String getParent()

retorna uma String com o diretório pai de um arquivo ou dir, o diretório onde o arquivo ou dir está localizado long length()

retorna o comprimento do arquivo em bytes long lastModified()

dependendo da plataforma, retorna uma representação de data/hora em que o arquivo ou dir foi modificado pela última vez String[] list()

retona um array de Strings representando o conteúdo de um diretório, retorna null se o objeto File não representar um diretório

Caracteres scape

Um caractere separador de caminho - barra invertida (\) - é utilizado para separar diretórios(dir) e arquivos(file) no caminho(path). Utilizar (\) como um separador de diretório em vez de "\\" numa "literal de String" é um erro de lógica. "\\" representa uma sequência scape utilizada para inserir (\) numa literal de String.

Page 4: Arquivos, Fluxos e Serialização de Objetos em Java

Caracteres separadores de linha específicos de cada plataforma

Para gerar saída de uma nova linha no texto do arquivo, cada plataforma pode ter um caractere específico, tais como: Windows...: (\r\n)

Linux/Mac.: (\n)

O especificador de formato (%n) pode ser usado em uma string de formato (printf()) para imprimir um

separador de linha específico da plataforma. O método System.out.println gera saída a um separador de linha específico da plataforma. Além disso, independentemente do separador de linha utilizado, um programa Java ainda pode reconhecer e ler as linhas de texto.

Fluxos e Transferência de dados Streams são fluxos de dados que viajam através de um canal de comunicação entre um programa e uma fonte de dados, a transferência de dados em Java é feita através de streams. Fontes das quais lemos dados são fluxos de entrada (in) e aquelas nas quais gravamos dados são fluxos de saída (out).

Processamento de Fluxos

Em Java são definidos dois tipos de processamento de Fluxos, Fluxos baseados em bytes e Fluxos baseados em caracteres. O processamento de Fluxos orientados por bytes é implementado pelas superclasses InputStream (fluxos de entrada) e OutputStream (fluxos de saída). O processamento de Fluxos orientados por caracteres é implementado pelas superclasses Reader (fluxos de entrada) e Writer (fluxos de saída).

Processamento de Arquivos

Arquivos são processados (leitura e gravação) por meio de Fluxos. O termo fluxo, para Arquivos, refere-se a dados ordenados que são lidos ou gravados em um meio magnético. O Java vê um Arquivo como um Fluxo Sequencial de bytes ou caracteres, cada Sistema Operacional fornece um mecanismo para determinar o término de um Arquivo, como um marcador de fim de arquivo ou uma contagem total de bytes no arquivo. O programa simplesmente recebe uma indicação do Sistema Operacional quando ele alcança o fim do fluxo.

Os Fluxos para Arquivos "baseados em bytes" representam os dados do Arquivo em formato binário. Os Fluxos para Arquivos "baseados em caracteres" representam os dados do Arquivo como uma sequência de caracteres (ASCII).

Page 5: Arquivos, Fluxos e Serialização de Objetos em Java

Com relação a dados numéricos, a diferença entre as duas formas é que no fluxo em bytes o valor numérico 5 pode ser utilizado em cálculos enquanto no fluxo em caracteres, 5 é simplesmente um valor literal que pode ser usado em uma string de texto. Arquivos criados utilizando Fluxos baseados em bytes são arquivos binários e Arquivos criados utilizando Fluxos baseados em caracteres são arquivos de texto. Arquivos de texto podem ser processados por editores de texto, enquanto arquivos binários são processados por programas que entendem seu conteúdo e ordenamento. Como o processamento de Arquivos é um subconjunto das capacidades de processamento de Fluxos, existem subclasses para cada uma destas hierarquias que tratam de tarefas de leitura e escrita específicas para Arquivos. O nome da subclasse é composto da sua especialidade seguido do tipo de transferência, por exemplo, a classe que faz a leitura de arquivos (files) do disco orientada por bytes (streams) chama-se FileInputStream e a orientada por caracteres, FileReader. Os programas realizam o Processamento de Arquivos em Java utilizando as classes do pacote java.io de acordo com a seguinte hierarquia: Arquivos com fluxos orientados por bytes, FileInputStream e FileOutputStream. Arquivos com fluxos orientados por caracteres, FileReader e FileWriter.

Abre-se um arquivo criando um objeto dessas Classes e o construtor do objeto interage com o Sistema Operacional para criá-lo.

Fluxos de entrada (in), saída (out) e erro (err)

Um programa Java abre (cria) um Arquivo criando e associando um Objeto ao fluxo de bytes ou caracteres. Quando um programa inicia a execução, o Java cria três objetos de fluxo que são associados a diferentes dispositivos: System.in objeto de fluxo de entrada padrão Leitura System.out objeto de fluxo de saída padrão Gravação

System.err objeto de fluxo de erro padrão Erro A classe System fornece os métodos setIn(), setOut() e setErr() para redirecionar os fluxos de entrada, saída e erro padrões.

Classes Scanner e Formatter

Além das classes FileReader e FileWriter do pacote java.io, a entrada e saída para Arquivo baseadas em caractere pode ser executada com as classes Scanner e Formatter. A Classe Scanner,

geralmente usada para entrada de dados a partir do teclado, também pode ler dados de um arquivo. A Classe Formatter permite que dados formatados sejam impressos em qualquer fluxo baseado em

caractere. Um objeto Formatter gera saída para strings formatadas de forma semelhante a printf().

Serialização de objetos A transferência de dados de objetos é feita a nível de bytes, um desmembramento dos dados é feito com a respectiva serialização e a integridade no transporte é garantida. Na leitura e gravação de arquivos sequenciais de texto, gravamos os campos de um registro (Classe) em um arquivo de texto a partir de um objeto registro (classe) na memória, depois lemos esses campos a partir do Arquivo colocando seus valores novamente em um objeto registro (classe) na memória. Quando a saída dos

Page 6: Arquivos, Fluxos e Serialização de Objetos em Java

campos do registro é gerada para o arquivo em disco, informações como tipo de dados são perdidas (não podemos saber se o texto 3 é um double, um int ou uma String), portanto temos em disco apenas dados sem informações sobre tipos. Caso uma leitura de arquivo soubesse a que tipo de objeto os dados correspondem, então eles seriam lidos e transferidos para o objeto desse tipo específico. Quando sabemos todas as informações a respeito de como os dados de um objeto são armazenados num arquivo, podemos recriar o objeto inteiro a partir de um arquivo. Para esse propósito existe o mecanismo de serialização de objetos. A serialização de objetos é realizada com fluxos baseados em bytes. Logo, arquivos que criam e manipulam objetos serão arquivos binários. Arquivos binários não podem ser visualizados nos editores de texto padrão, portanto é necessário escrever um aplicativo que seja capaz de ler e exibir objetos serializados. Um objeto serializado é um objeto representado como uma sequencia de bytes que inclui os dados do objeto bem como o tipo de objeto e também as informações sobre os tipos dos dados armazenados no objeto. Após um objeto serializado ser gravado em um arquivo, ele pode ser lido a partir do arquivo e desserializado, ou seja, as informações dos tipos e os bytes que representam o objeto e seus dados podem ser utilizados para recriar o objeto registro na memória uma vez que o mecanismo de serialização cria cópias exatas dos objetos sem a necessidade de sobrescrever o método Object clone().

Interface Serializable

Para que objetos registros (classes) possam ser serializados, é necessário que implementem a interface Serializable, uma <interface de tags > que não contém nenhum método. Uma Classe que a

implemente é marcada com tags como um objeto Serializable assegurando que um ObjectOutputStream possa enviá-lo para um fluxo de saída. Uma Classe que implemente Serializable, deve se assegurar de que cada variável de instância seja um tipo serializável, do contrário deve ser declarada transient para indicar que não é serializável e ser ignorada durante o processo de serialização. Por padrão, todas as variáveis de tipo primitivo são serializáveis.

Classes ObjectInputStream e ObjectOutputStream

As classes ObjectInputStream e ObjectOutputStream são utilizadas para realizar a leitura e gravação de objetos inteiros com fluxos de bytes. A fim de utilizar a serialização para leitura e gravação de objetos em Arquivos, essas classes são inicializadas juntamente com as classes de Arquivos baseadas em fluxos de bytes FileInputStream e FileOutputStream. Esse tipo de inicialização de objetos de fluxos com outros objetos de fluxos é chamada de empacotamento. O novo objeto de fluxo a ser criado empacota o objeto de fluxo passado como argumento do construtor e o utiliza para gravar os objetos em Arquivo. new ObjectInputStream(FileInpuStream);

Page 7: Arquivos, Fluxos e Serialização de Objetos em Java

ObjectInputStream .readObject(Object obj)

Lê e retorna uma referência a um Object a partir do Arquivo. É o método responsável pela leitura de arquivos binários. Depois que o registro é lido, podemos fazer uma coerção da sua referência para o tipo real do objeto. ObjectOutputStream .writeObject(Object obj) Recebe um Object como argumento e grava todas as suas informações em Arquivo com apenas uma instrução. ObjectOutputStream.close() Fecha tanto o ObjectOutputStream ou ObjectInputStream como o FileOutputStream ou FileInputStream empacotado.

Ao utilizar fluxos empacotados, fechar o fluxo mais externo também fecha o fluxo subjacente.

Classes adicionais do pacote java.io para fluxos

Interfaces e Classes para entrada e saída de fluxos baseados em bytes

Page 8: Arquivos, Fluxos e Serialização de Objetos em Java

Interfaces e Classes para entrada e saída de fluxos baseados em caracteres

Classe JFileChooser

A classe JFileChooser exibe uma caixa de diálogo oferecendo uma Interface Gráfica que permite ao

usuário selecionar arquivos ou diretórios.

JFileChooser.setFileSelectionMode()

Especifica o que o usuário pode selecionar no fileChooser, seu parâmetro recebe uma constante como argumento que inclui FILES_AND_DIRECTORIES, FILES_ONLY (default) e DIRECTORIES_ONLY.

Page 9: Arquivos, Fluxos e Serialização de Objetos em Java

JFileChooser.showOpenDialog()

Exibe o diálogo modal - não permite ao usuário interagir com nenhuma outra janela até que o diálogo seja fechado clicando em open ou cancel, e retona um inteiro especificando em qual botão o usuário clicou para fechar o diálogo. JFileChooser.getSelectedFile()

Recupera o arquivo selecionado pelo usuário no diálogo.