Arquivos e Streams Porto Alegre Alegre,, novembro de 2006 Adaptado das aulas dos Profs: Isabel Manssour, Luciana Nedel, Bernardo Copstein e Júlio Machado Roteiro n Introdução a Arquivos n Streams n Serialização n Arquivos de Acesso Randômico n Exercícios Introdução a Arquivos n Armazenamento n Dados em vetores, listas e variáveis n Arquivos n n n n Perdidos quando acaba a execução do programa Armazenamento permanente de dados Dados persistentes Dispositivos de armazenamento secundários n n Armazenam arquivos Discos magnéticos, discos ópticos, fitas magnéticas ‹# › Introdução a Arquivos n Hierarquia de dados n Campo (Field) n n n Conjunto de caracteres com o mesmo significado Exemplo: nome Registro (Record) Conjunto de campos relacionados Exemplo: nome, endereço, idade, telefone de uma pessoa n Representado por uma instância de uma classe n n Introdução a Arquivos n Hierarquia de dados n Arquivo (File) n n n Conjunto de registros relacionados Exemplo: informações sobre um grupo de pessoas Base de dados (Database) n n Conjunto de arquivos relacionados Exemplo: folha de pagamento, controle de estoque, controle de contas Introdução a Arquivos Ficha Nome: ____ Endereço: _____ Telefone: ______ CIC: ______ RG: _______ Registro Campos Campo Registro Endereço Telefone CIC RG Ana Silva Nome Andradas 34 332.56.35 345.565/9 271646252 João Neto Siqueira 34 353.46.54 454.567/8 456546568 Maria Santos Ipiranga 67 223.66.51 028.480/8 873260269 : : : : : Arquivo ‹# › Introdução a Arquivos n Chave primária Apresenta um valor diferente para cada registro do arquivo n A partir de uma chave primária identifica-se um único registro no arquivo n Introdução a Arquivos n Chave de acesso Facilita a recuperação de registros Usada para identificar o registro desejado em uma operação de acesso a um arquivo n Um campo é escolhido como chave de acesso n n Identifica um registro (entidade única dentre todos os outros registros) n Exemplo: número do CPF n Introdução a Arquivos n Chave de ordenação n n É a chave primária usada para estabelecer a seqüência na qual devem ser dispostos os registros de um arquivo Chave secundária n Difere de uma chave primária pela possibilidade de ter valores iguais para as chaves ‹# › Introdução a Arquivos n Arquivo seqüencial Todos os registros estão organizados na forma de uma lista, um depois do outro n Os registros podem estar dispostos ordenadamente, obedecendo a seqüência determinada pela chave primária n É possível incluir, excluir, alterar e consultar os registros n Introdução a Arquivos n Arquivo seqüencial n Exemplo: Nome: João End: ____ Fone: ____ Válido: V Nome: Maria End: ____ Fone: ____ Nome: José End: ____ Fone: ____ Nome: Ana End: ____ Fone: ____ Nome: Paulo E End: ____ O Fone: ____ Válido: V Válido: V Válido: V Válido: V F Todos os registros possuem o mesmo tamanho e são armazenados seqüencialmente na memória Introdução a Arquivos n Arquivo seqüencial n Inclusão no final Nome: João End: ____ Fone: ____ Válido: V Nome: Maria Nome: José End: ____ End: ____ Fone: ____ Fone: ____ Nome: Ana End: ____ Fone: ____ Nome: Paulo Nome: Rita End: ____ End: ____ Fone: ____ Fone: ____ Válido: V Válido: V Válido: V Válido: V Válido: V E O F ‹# › Introdução a Arquivos n Arquivo seqüencial n Exclusão lógica: Maria Nome: João End: ____ Fone: ____ Válido: V n Nome: Maria Nome: José End: ____ End: ____ Fone: ____ Fone: ____ Nome: Ana End: ____ Fone: ____ Nome: Paulo Nome: Rita End: ____ End: ____ Fone: ____ Fone: ____ Válido: F Válido: V Válido: V Válido: V Válido: V E O F Exclusão física Nome: João End: ____ Fone: ____ Válido: V Duplica os registros Nome: Maria End: ____ Fone: ____ Válido: V Nome: José End: ____ Fone: ____ Válido: V Nome: Ana End: ____ Fone: ____ Válido: V Nome: Paulo End: ____ Fone: ____ Válido: V Nome: Rita End: ____ Fone: ____ Válido: V E O F Nome: João End: ____ Fone: ____ Válido: V Nome: José End: ____ Fone: ____ Válido: V Nome: Ana End: ____ Fone: ____ Válido: V Nome: Paulo End: ____ Fone: ____ Válido: V Nome: Rita End: ____ Fone: ____ Válido: V E O F Introdução a Arquivos n Arquivo seqüencial n Pesquisa seqüencial Nome: João End: ____ Fone: ____ Válido: V n Nome: Maria Nome: José End: ____ End: ____ Fone: ____ Fone: ____ Nome: Ana End: ____ Fone: ____ Nome: Paulo Nome: Rita End: ____ End: ____ Fone: ____ Fone: ____ Válido: V Válido: V Válido: V Válido: V Válido: V E O F Acesso direto n Contar os bytes... Introdução a Arquivos n Arquivo de índice Consiste em um arquivo que guarda o campo chave e a posição do registro no disco n Exemplo: n E100 E101 Nome: João End: ____ Fone: ____ Válido: V Nome: Maria Nome: José End: ____ End: ____ Fone: ____ Fone: ____ Válido: F E102 E103 Nome: Ana End: ____ Fone: ____ Válido: V Válido: V Arquivo de Dados E104 E105 Nome: Paulo Nome: Rita End: ____ End: ____ Fone: ____ Fone: ____ Válido: V Válido: V E O F E Chave: Ana Chave: João Chave: José Chave: Maria Chave: Paulo Chave: Rita O Posição: E103 Posição: E100 Posição: E102 Posição: E101 Posição: E104 Posição: E105 F Arquivo de Índice ‹# › Introdução a Arquivos n Arquivos de índice n n Permitem o acesso rápido às dados Vários podem ser criados Índice por nome Índice por idade n Índice por telefone n ... n n Introdução a Arquivos n Arquivo binário n n Os dados são armazenados em disco utilizando o mesmo formato binário de armazenamento em memória Arquivo texto n Os dados são armazenados em disco em registros de um único byte (um caractere ASCII) Introdução a Arquivos n Programas que trabalham com arquivos devem permitir Incluir, excluir, consultar e alterar registros Incluir novos campos nos registros n Excluir campos dos registros n n n Todas estas tarefas exigem muita programação ‹# › Introdução a Arquivos n Portanto, para facilitar este gerenciamento foi criado o SGBD - Sistema Gerenciador de Banco de Dados Ferramenta cujo objetivo principal é gerenciar o acesso e a correta manutenção dos dados armazenados no banco de dados n Exemplos: Oracle, Access, Sybase, etc. n Roteiro n Introdução a Arquivos n Streams n Serialização n Arquivos de Acesso Randômico n Exercícios Streams n Criar um bom sistema de E/S é uma das tarefas mais delicadas na programação Existem diversas abordagens diferentes Deve-se tratar várias origens e destinos para os dados (console, disco, impressora, conexão de rede,...). n Existem vários modos de acesso (seqüencial, randômico, com ou sem buffer, por linhas, por palavras, binário ou caractere,...) n n ‹# › Streams n Java provê uma biblioteca com muitas classes, cada uma com um propósito diferente n Pacote java.io.* Streams n Stream (fluxo) de E/S n Gera o caminho por meio do qual os programas podem enviar uma seqüência de bytes de uma fonte até um destino Programa escreve i n f o r m a ç ã o Destino um stream Fonte informação um stream n n lê Programa Normalmente associados a arquivos Teclado, mouse, memória, vídeo ou impressora também podem ser uma fonte ou destino Streams Streams (fluxo de bytes) Impressora Teclado Monitor Aplicação Java HD Mouse ‹# › Streams n Java Cada arquivo é um fluxo seqüencial de bytes A ca b a co m u m “m a rca d o r d e fim d o a rq u ivo ” (endof-file), ou n Acaba em um número específico de bytes (registrado em uma estrutura de dados mantida pelo sistema) n n Programa que processa fluxo de bytes recebe uma indicação quando alcança o final do fluxo n Abertura de um arquivo em Java n n Cria um objeto e associa um fluxo de bytes a este objeto Streams n Objetos stream automaticamente criados quando um programa java é executado: System.in - standard input (inserção de bytes via teclado) n System.out - standard output (saída de dados na tela) n System.err - standard error (saída a mensagens de erro na tela) n Podem ser redirecionados para disco, por exemplo n Fornecem canais de comunicação n Streams n Streams Permite a comunicação de programas Java com o meio externo (além da console e dos componentes para interfaces gráficas) n Lidam apenas com entrada ou saída de bytes n n Fluxos de byte: tratam entrada ou saída de 8 bits n Fluxos de caractere: tratam entrada ou saída de 16 bits n n Classes InputStream, OutputStream Classes Reader, Writer ‹# › Streams n Fluxos de byte Streams n Fluxos de bytes: n São subclasses de InputStream e OutputStream n n n Classes abstratas Definem métodos para entrada e saída Estas classes, bem como as várias classes para trabalhar com arquivos, estão no pacote java.io Streams n Arquivos são abertos criando-se objetos das classes FileInputStream (para leitura) e FileOutputStream (para escrita) n Exemplo: FileInputStream a = new FileInputStream ("arq.dat"); FileOutputStream b = new FileOutputStream("c:/java/arq.dat"); Ao criar o arquivo, um stream é associado ao objeto n Estas classes possuem apenas os métodos read/write para ler e gravar bytes de arquivos de entrada/saída (arquivos binários) n ‹# › Streams n Leitura de dados diretamente como bytes n n Rápido mas complicado Usualmente lê-se dados como agregados de bytes que formam um int, um double, etc. Streams n Para ler/gravar tipos de dados mais elaborados é necessário associar filtros aos Streams n n Java oferece diversas classes filtro para serem conectadas no stream básico Classes filtro para realizar E/S de tipos de dados primitivos n n DataInputStream e DataOutputStream Usados junto com as classes de fluxo de arquivo Arquivo Apenas métodos read/write para ler e gravar bytes FileInputStream FileOutputStream DataInputStream DataOutputStream Memória Permitem ler/gravar tipos de dados mais elaborados, pois possuem métodos para E/S de inteiros, reais etc. Streams Aplicação Java (int, float, ...) Aplicação Java (int, float, ...) Streams (fluxo de bytes) Streams (fluxo de bytes) HD (arquivo) HD (arquivo) ‹# › Streams n n As classes DataInputStream/DataOutputStream possuem métodos para E/S de tipos de dados primitivos, tais como inteiros e reais E/S de dados binários n DataInputStream n n n DataOutputStream n n n Lê bytes de InputStream Métodos read, readByte, readChar, readDouble, readUnsignedShort... Escreve bytes em OutputStream Métodos write, writeChar, writeChars, writeBoolean, writeInt... Exemplo: Streams import java.io.*; class StreamTest{ public void gravaDados( ){ try{ FileOutputStream fos=new FileOutputStream("dados.dat"); DataOutputStream dos = new DataOutputStream(fos); dos.writeInt(10); dos.writeInt(20); dos.writeDouble(3.14); dos.writeLong(123456789); dos.close(); } catch(IOException e){ System.out.println("File error: "+e.getMessage()); } } (continua...) Streams (...continua) public void leDados(){ try{ FileInputStream fis = new FileInputStream("dados.dat"); DataInputStream dis = new DataInputStream(fis); System.out.println("Dados: " +dis.readInt()+":"+dis.readInt()+":" +dis.readDouble()+":" +dis.readLong()); dis.close(); } catch(IOException e){ System.out.println("File error: "+e.getMessage()); } } (continua...) ‹# › Streams (...continua) public static void main(String args[]){ StreamTest st = new StreamTest(); st.gravaDados(); st.leDados(); } } Roteiro n Introdução a Arquivos n Streams n Serialização n Arquivos de Acesso Randômico n Exercícios Serialização n Podemos armazenar os dados em arquivos ou em bancos de dados n Esse tipo de procedimento não apresenta problemas quando os dados a serem gravados são tipos primitivos, mas os problemas começam quando se tenta armazenar referências para objetos ‹# › Serialização n Normalmente, para armazenar uma estrutura de memória que se utilize de referências (como por exemplo, estruturas encadeadas) é preciso armazenar todos os tipos de dados primitivos iso la d a m e n te ju n ta m e n te co m a lg u m tip o d e “ch a ve d e a ce sso ”. n Não é possível armazenar diretamente referências porque as mesmas são baseadas em endereços de memória e a própria ordem em que se carrega os objetos pode implicar em que eles sejam alocados em posições de memória diferentes daquelas que ocupavam quando foram gravados. Serialização n Pior, os objetos podem ser gravados por um programa e lidos por outro. Neste caso certamente os endereços de memória serão diferentes. n A solução é serializar os objetos, ou seja, gravá-los de maneira que na hora de restaurá-los seja possível recriar as instâncias e reconectá-las da maneira correta. Serialização n A maneira de fazer isso é implementar a interface Serializable n n n Esta interface não tem métodos Serve apenas para indicar que os atributos deste objeto podem ser serializados e deserializados A leitura/gravação de objetos serializáveis é feita através das classes ObjectInputStream e ObjectOutputStream. ‹# › Serialização n Passo 1: declarar o objeto como serializável: import java.io.Serializable; class Dados implements Serializable{ private int dado; public Dados(int n){ dado = n; } public void imp(){ System.out.println("Dado = "+dado); } } Serialização n Passo 2: gravar o objeto usando ObjectOutputStream: Dados dado = new Dado(20); try{ FileOutputStream os = new FileOutputStream(“teste"); ObjectOutputStream oarq = new ObjectOutputStream(os); oarq.writeObject(dado); oarq.close(); }catch(IOException e){ System.out.println(e.getMessage()); e.printStackTrace(); } Serialização n Passo 3: carregar o objeto usando ObjectInputStream: Dados dadol; try{ FileInputStream is = new FileInputStream(“teste"); ObjectInputStream iarq = new ObjectInputStream(is); dadol = (Dados) iarq.readObject(); iarq.close(); }catch(IOException e){ System.out.println(e.getMessage()); e.printStackTrace(); } dadol.imp(); ‹# › Roteiro n Introdução a Arquivos n Streams n Serialização n Arquivos de Acesso Randômico n Exercícios Arquivos de Acesso Randômico n Arquivos de acesso randômico (ou aleatório) podem ser criados com auxílio da classe RandomAccessFile n Arquivo de acesso randômico Permite ler a partir de qualquer posição no arquivo n Acesso rápido n Arquivos de Acesso Randômico n A classe RandomAccessFile permite não apenas acesso direto a posições específicas do arquivo (em bytes), como também permite que se trabalhe n o s m o d o s “le itu ra ” (r), “g ra va çã o ” (w ) o u “le itu ra e g ra va çã o ” (rw ) n A classe RandomAccessFile possui métodos semelhantes a DataInputStream e DataOutputStream n Podem ser inseridos novos dados sem destruir os dados previamente gravados ‹# › Arquivos de Acesso Randômico n Implementados usando registros de tamanho fixo n Como um trem com vários vagões n Facilita o cálculo da localização exata de qualquer registro em relação ao início do arquivo n 0 Alguns cheios e outros vazios 1 0 0 2 0 0 3 0 0 4 0 0 5 0 0 } b y teo ffsets } } } } } } 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 b y tes b y tes b y tes b y tes b y tes b y tes Aqui,os registros possuem 100 bytes cada (um não irá jamais sobrescrever o outro). Arquivos de Acesso Randômico n Classe RandomAccessFile n Faz o mesmo que DataInputStream e DataOutputStream n n Pode ler/escrever dados binários Ao associar RandomAccessFile a um arquivo Dados são lidos/escritos na localização do arquivo especificada pelo ponteiro de posição no arquivo (ou file pointer) n Todos os dados são tratados como tipos primitivos n n Tem tamanho fixo (double é 8 bytes, int é 4, etc.) Arquivos de Acesso Randômico n Para posicionar o ponteiro de posição sobre um ponto específico do arquivo utilize o método seek. n Exemplo: n Método que lê diretamente um double armazenado após 2 int. ‹# › Arquivos de Acesso Randômico public void leDoubleApos2Ints(){ try{ RandomAccessFile rf = new RandomAccessFile("dados.dat","r"); rf.seek(4*2); System.out.println("Valor do Double: "+rf.readDouble()); rf.close(); } catch(IOException e){ System.out.println(e.getMessage()); } } Arquivos de Acesso Randômico n Para acrescentar dados em um arquivo basta abri-lo para leitura e gravação e posicionar o ponteiro de posição no fim do arquivo. n Exemplo: Arquivos de Acesso Randômico public void acrescentaInt(int i){ try{ RandomAccessFile rf = new RandomAccessFile("dados.dat","rw"); rf.seek(rf.length()); rf.writeInt(i); rf.close(); } catch(IOException e){ System.out.println(e.getMessage()); } } ‹# › Arquivos de Acesso Randômico Para ler dados de um arquivo de tamanho desconhecido, trate EOFException. n Exemplo: n public void leArq(){ FileInputStream is = null; DataInputStream dis = null; int aux; leDados(); (continua...) Arquivos de Acesso Randômico try{ is = new FileInputStream("dados.dat"); dis = new DataInputStream(is); while(true){ aux = dis.readInt(); System.out.println(aux); } } catch (EOFException e){ } catch (IOException e){ System.out.println(e.getMessage()); } try {dis.close(); } catch (IOException e){ System.out.println(e.getMessage()); } } Roteiro n Introdução a Arquivos n Streams n Serialização n Arquivos de Acesso Randômico n Exercícios ‹# › Exercícios 1) Implemente um método em JAVA que recebe um ArrayList do tipo Ponto como parâmetro e armazena os pontos em um arquivo chamado pontos.dat. Em primeiro lugar deve ser armazenada a quantidade de pontos e, na seqüência, a lista de pontos (primeiro todas as ordenadas, depois todas as abscissas). 2) Implemente um método em JAVA que seja capaz de ler um arquivo criado pelo método do exercício 2. O método deve devolver um ArrayList do tipo Ponto com os pontos lidos. Exercícios 3) Faça um método JAVA que recebe uma string com o nome de um arquivo e uma lista encadeada por parâmetro. Este método deverá gravar a lista em um arquivo binário. 4) Faça um método JAVA que recebe uma string com o nome de um arquivo e uma lista encadeada por parâmetro. Este método deverá ler a lista do arquivo cujo nome é passado por parâmetro. ‹# ›