Arquivos Estruturas de Dados II – Vanessa Braganholo Entidades } Aplicações precisam armazenar dados sobre as mais diversas entidades, que podem ser concretas ou abstratas } } } } Funcionário de uma empresa (concreto) Carros de uma locadora de veículos (concreto) Contas-corrente dos clientes de um banco (abstrato) Ligações telefônicas dos clientes de uma empresa de telefonia (abstrato) Atributos } Cada uma dessas entidades pode ser descrita por um conjunto de atributos } } } } } Funcionário: nome, CPF, data-nascimento, salário Carro: marca, modelo, ano-fabricação, placa Conta-Corrente: agência, conta, saldo Ligações Telefônicas: data, origem, destino, duração Os atributos também podem ser chamados de campos Registros Indivíduos dessas entidades possuem um valor para cada um desses atributos (chamados de pares atributovalor) } Um conjunto de pares atributo-valor que identifica um indivíduo de uma entidade é chamado de registro } Exemplos de Registros Funcionário: <nome, João>, <CPF, 012345678-90>, <data-nascimento, 10/04/1980>, <salário, 3000> } Carro <marca, Honda>, <modelo, Fit>, <ano-fabricação, 2010>, <placa, XYZ0123> } Conta-Corrente <agencia, 0123>, <conta, 123456>, <saldo, 2000> } Ligação Telefônica <data, 01/07/2010>, <origem, 21-2598-3311>, <destino, 21-2589-3322>, <duração, 10’36”> } Tabela Uma tabela é um conjunto ordenado de registros. Uma tabela pode ser armazenada em memória principal ou em memória secundária (disco) } Nesse segundo caso, também costuma ser chamada de arquivo } Exemplo: Arquivo de Funcionários Nome CPF Data-­‐Nascimento Salário João 012345678-­‐90 10/04/1980 3000 Maria 234567890-­‐12 25/07/1978 5000 Lúcia 345678901-­‐23 27/04/1981 1500 IMPORTANTE: Todos os registros de uma mesma tabela possuem a mesma estrutura (mesmo conjunto de atributos/campos) Problema: encontrar registros } Problema comum de diversas aplicações: encontrar um ou mais registros em uma tabela } } } Encontrar o empregado Maria Encontrar todos os empregados que ganham 3000 Encontrar todos os empregados que nasceram em 27/04/1981 Conceito de Chave Dados usados para encontrar um registro: chave } Chave: subconjunto de atributos que identifica um determinado registro } Chave Primária e Secundária } Chave primária: subconjunto de atributos que identifica unicamente um determinado registro Exemplo: CPF do funcionário ou RG do funcionário } } } Na hipótese de uma chave primária ser formada por uma combinação de campos, essa combinação deve ser mínima (não deve conter campos supérfulos) Eventualmente, podemos encontrar mais de uma combinação mínima de campos que forma uma chave primária Chave secundária: subconjunto de atributos que identificam um conjunto de registros de uma tabela Exemplo: Nome do funcionário Tabelas } Aplicações reais lidam com várias tabelas, cada uma delas representando uma entidade } Uma aplicação de controle bancário precisaria de quais tabelas? Aplicação Bancária } Uma aplicação de controle bancário precisaria de quais tabelas? } } } Cliente Agência Conta-Corrente Certa redundância é necessária Neste caso, é necessário correlacionar os dados, para que seja possível saber que conta pertence a que agência, e que conta pertence a que cliente } Para isso, é usual repetir algum dado (um código,por exemplo) no outro arquivo } } } } Cliente: CodCliente, Nome, CPF, Endereço Agência: CodAgencia, NumeroAgencia, Endereco Conta-Corrente: CodAgencia, CodCliente, CodConta, NumeroConta, Saldo Certa redundância é necessária Neste caso, é necessário correlacionar os dados, para que seja possível saber que conta pertence a que agência, e que conta pertence a que cliente } Para isso, é usual repetir algum dado (um código,por exemplo) no outro arquivo } } } } Cliente: CodCliente, Nome, CPF, Endereço Agência: CodAgencia, NumeroAgencia, Endereco Conta-Corrente: CodAgencia, CodCliente, CodConta, Numero Conta, Saldo Quais são as chaves primárias e secundárias deste exemplo? Aplicação Financeira } Chaves primárias: } } } } Chaves primárias alternativas: } } } } Cliente: CodCliente Agência: CodAgencia Conta-Corrente: CodAgencia E CodConta Cliente: CPF Agência: NumeroAgencia Conta-Corrente: NumeroConta Chaves secundárias: } } } Cliente: Nome Agência: Endereço Conta-Corrente: CodAgencia OU CodCliente OU Saldo Discussão sobre chaves } Por quê não usar CPF como chave primária de cliente? Por quê os atributos artificiais (código)? Exercício Deseja-se automatizar uma locadora de automóveis. A locadora possui filiais espalhadas por todo país. Cada filial possui um código que a identifica, um telefone e um endereço. Cada filial da locadora sedia um conjunto de veículos que ela aluga. O veículo é identificado por um número sequencial que o distingue dos demais veículos da filial. Para o veículo é importante saber a placa, data de vencimento do seguro, nome do modelo, número de portas e se possui ar-condicionado ou não. Quando um veículo é alugado é fechado um contrato de aluguel. Cada contrato possui um número identificador, uma data de saída do veículo, uma data de retorno provável, para veículos ainda não retornados, e uma data de retorno efetivo, para veículos já retornados. O contrato é feito para um veículo e um cliente. Para os clientes é preciso armazenar seu nome, CPF, endereço, o telefone, bem como o número e data de expiração de seu cartão de crédito. Exercício } Para o cenário das locadoras, identificar: } } } Entidades Atributos Chaves primárias Discussão } Por que não usar uma única tabela? Banco de Dados } Esse conjunto de arquivos pode ser considerado um banco de Dados? Características de um Sistema de Gerência de Banco de Dados } } } } Natureza auto-descritiva do sistema de banco de dados: banco de dados possui um catálogo onde estão descritas as estruturas e tipos de dados de cada tabela e suas restrições – ex. quais são as chaves primárias de cada tabela Isolamento entre os programas e os dados, e a abstração dos dados: em programação com arquivos a estrutura dos arquivos é embutida dentro das aplicações. Isso não acontece quando se usa banco de dados. Suporte para as múltiplas visões dos dados: usuários diferentes podem ver porções diferentes dos dados Compartilhamento de dados e processamento de transações multi-usuários Características de um Sistema de Gerência de Banco de Dados } } } } Natureza auto-descritiva do sistema de banco de dados: banco de dados possui um catálogo onde estão descritas as estruturas e tipos de dados de cada tabela e suas restrições – ex. quais são as chaves primárias de cada tabela Isolamento entre os programas e os dados, e a abstração dos dados: em programação com arquivos a estrutura dos arquivos é embutida dentro das aplicações. Isso não acontece quando se usa banco de dados. Suporte para as múltiplas visões dos dados: usuários diferentes podem ver porções diferentes dos dados Compartilhamento de dados e processamento de transações multi-usuários NÃO É O NOSSO FOCO NESSA DISCIPLINA! Níveis de Organização das tabelas/arquivos Organização Lógica dos dados: é a visão que o usuário tem dos dados, com base em entidades, seus atributos e seus relacionamentos } Organização Física dos dados: é a maneira pela qual as informações ficam armazenadas nos dispositivos periféricos (disco, pen-drive, etc.) } Dependência entre programas e dados Os programas de computador são mais ou menos dependentes da organização física dos dados } Eles podem ser classificados em quatro categorias } Categoria 1: Programas Dependentes dos Dados Programas têm acesso aos dados especificando endereços absolutos de células de armazenamento } Se os dados mudarem de lugar, os programas que os acessam precisam ser modificados } Ocorre nas chamadas de baixo nível dos sistemas operacionais } Exemplo: informação sobre espaço livre em um arquivo em um sistema operacional pode ser guardada em um bloco particular do disco } Categoria 2: Independência Física dos Dados Programas acessam a memória pelo nome e não por endereço (memória primária), ou pela posição relativa ao início do arquivo (memória secundária) } O mapeamento (nome → endereço) é feito pelo sistema operacional } Exemplo: programas escritos em linguagens de Terceira Geração que só precisam conhecer a organização lógica dos dados (C, Java, Pascal...) } Programas dependem da estrutura lógica dos arquivos } Categoria 3: Independência Lógica Parcial dos Dados Programas desta categoria podem operar sobre diversos arquivos (com estruturas diferentes) sem serem modificados. } Estes programas buscam a estrutura dos dados nas informações disponíveis no meio do armazenamento e fazem uma adaptação em tempo de execução do programa. } Caso a adaptação ocorresse em tempo de compilação, seria o caso de programas de categoria 2 } Exemplo de operação: ler o próximo registro de um arquivo qualquer } Categoria 4: Independência Lógica dos Dados Programas dessa categoria armazenam a descrição dos dados junto com eles } Por isso, os programas não necessitam definir a estrutura dos dados } Exemplo: programas que utilizam SGBDs } Operações sobre arquivos } Programas que lidam com arquivos realizam os seguintes tipos de operações sobre eles: } } } } } } Criação: alocação e inicialização da área de dados, assim como de seus descritores Destruição: liberação da área de dados e descritores usados na representação da tabela Inserção: inclusão de novo registro na tabela Exclusão: remoção de um registro da tabela Alteração: modificação dos valores de um ou mais atributos/ campos da tabela Consulta: obtenção dos valores de todos os campos de um registro, dada uma chave de entrada Refrescando a memória… Tutorial sobre Manipulação de Arquivos em Java Fonte: http://download.oracle.com/javase/tutorial/essential/io IDE Java: NetBeans I/O Stream } } Um I/O Stream em Java representa uma fonte de entrada ou saída destino Um stream pode representar diferentes tipos de fonte ou destino: } } } } } } Arquivos em disco Dispositivos Outros programas Estruturas em memória … Suportam diferentes tipos de dados: } } } } Bytes Tipos primitivos de dados (inteiros, strings, …) Caracteres Objetos I/O Stream Independente de como funcionam internamente, todos os streams seguem um modelo simples de interação com programas } Um stream é uma sequencia de dados } } } Para leitura: input stream Para gravação: output stream I/O Input Stream } Um programa utiliza um Input Stream para ler dados de uma fonte, um item de cada vez I/O Output Stream } Um programa utiliza um Output Stream para gravar dados em um destino, um item de cada vez Na nossa disciplina } } Fonte e destino são arquivos Exemplo de arquivo a ser manipulado xanadu.txt In Xanadu did Kubla Khan A stately pleasure-dome decree: Where Alph, the sacred river, ran Through caverns measureless to man Down to a sunless sea. Byte Streams } Permitem realizar entrada e saída de bytes de 8bits ByteStream: Como funciona… Exemplo } Ver arquivo CopyBytes.java } NOTA: Método read() retorna um int ao invés de um byte Isso acontece para que seja possível o método retornar -1 quando o stream terminar } Considerações sobre o exemplo } Sempre feche os streams utilizados } } Ao fechá-los, vc libera a memória consumida por eles Pode ocorrer erro ao abrir o InputStream ou o OutputStream (ou ambos) } Por isso é importante testar se são diferentes de null antes de fechá-los ByteStream Muito baixo nível } Existem outros tipos de stream para tratar outros tipos de dados } } Mas são importantes porque todos os outros são construídos sobre ele } Nosso arquivo exemplo é um arquivo de texto, então vamos modificar o programa um pouco para tratar isso Character Stream Mesmo princípio de funcionamento do ByteStream } Faz conversão automática da representação dos caracteres em Java (que usa Unicode) para o enconding de caracteres local } } Ver aquivo CopyCharacter.java } Principais diferenças entre este exemplo e o anterior: } } Uso de FileReader ao invés de FileInputStream Uso de FileWriter ao invés de FileOutputStream Entrada e Saída } Neste exemplo, o disco é acessado para ler cada caractere do arquivo, e depois novamente para gravar cada caractere } } MUITO LENTO!! Solução: utilizar BufferedStreams } O sistema operacional faz I/O apenas quando o Buffer está vazio I/O Orientada a linhas Para arquivos texto, é possível ler linhas inteiras de uma só vez, usando um buffer: BufferedReader (para leitura) e PrintWriter (para gravação) } Linha: } } } } } delimitada por um CR ou LF ("\r\n") delimitada por CR ("\r") delimitada por LF ("\n") Ver arquivo CopyLines.java Foco da disciplina } Arquivos binários ao invés de arquivos texto } Como implementar um programa que grava registros de funcionários, e depois lê esses registros? } Usar DataStreams } Possuem métodos específicos para ler/gravar tipos específicos (inteiro, string, etc) DataStreams } Exemplo do funcionário Primeiro problema: em Java não existe o conceito de registro } Solução de contorno: } } Criar uma classe Funcionário com os atributos do funcionário Classe Funcionário public class Funcionario { public int codFuncionario; public String nome; public String cpf; public String dataNascimento; public float salario; } NOTA IMPORTANTE: não é uma boa prática de programação utilizar atributos públicos nas classes. Na disciplina, vamos adotar esta opção apenas para simplificar os exemplos. O correto seria implementar métodos get e set para cada atributo. Manipulação } DataStream detecta final de arquivo lançando uma exceção java.io.EOFException } } } Lógica para testar final de arquivo agora não é mais baseada no teste de valor -1 Capturar a exceção e fechar o DataStream Ver arquivo ManipulaFuncionario.java Exercício Alterar a classe ManipulaFuncionario para ler os dados do funcionário a ser gravado do teclado (atenção: criar uma nova classe! Não sobre-escrever a classe!) } A cada funcionário informado, perguntar se deseja ler os dados de mais um funcionário } } } Se sim, ler mais um funcionário Se não, gravar todos os funcionários lidos Orientação a objetos } Exemplo anterior fere os princípios de orientação a objetos } Ideal é dar a responsabilidade de ler registro e gravar registro à classe Funcionário } Ver arquivo FuncionarioOO.java Ver arquivo ManipulaFuncionarioOO.java } Flush Os métodos que utilizam buffer para gravação só fazem a gravação em disco quando o buffer está cheio } Às vezes é necessário ter mais controle sobre quando os dados realmente serão gravados } } } AutoFlush: Algumas classes buffered output (ex. PrintWriter) possuem um atributo autoFlush. Quando este atributo está ligado (true), o buffer é gravado em disco a cada vez que uma operação println é executada Alternativa: Método flush força gravação do buffer em disco Fonte } http://download.oracle.com/javase/tutorial/essential/io Pratique! } Execute os códigos dos exemplos deste tutorial em casa Exercício Modifique as classes para lidar com registros de contacorrente } Dois arquivos: } } } } } } Agência (Cod, Nome, Gerente) Conta-Corrente (Cod, CodAgencia, Saldo) Usuário deve poder escolher o que quer cadastrar Dados devem ser lidos do teclado Aplicação deve ter opção de Cadastrar, Ler ou Sair