Skip to content

Latest commit

 

History

History
214 lines (154 loc) · 16 KB

File metadata and controls

214 lines (154 loc) · 16 KB

17 Arquivos e Fluxos

17.1 Introdução

As varáveis e os arrays oferecem apenas armazenamento temporário dos dados. Em comparação, os arquivos são usados par armazenamento de longo prazo de grandes volumes de dados e podem mantê-los mesmo depois que o programa que os criou termina. Os dados mantidos em arquivos são frequentemente chamados de dados persistentes.
Neste capítulo explicaremos como criar, atualizar e processar arquivos de dados em programas C#.
Consideraremos os arquivos de "acesso sequencial" e os arquivos de "acesso aleatório", indicando os tipos de aplicativos para os quais cada um é mais conveniente.
Temos dois objetivos neste capítulo: apresentar os paradigmas do processamento de arquivos de acesso sequencial e de acesso aleatório e fornecer ao leitor recursos de processamento de fluxo suficientes para suportar os recursos de redes que apresentaremos no Capítulo 22

O processamento de arquivos é um dos recursos mais importantes de uma linguagem de programação, pois ele permite que a linguagem suporte aplicativos comerciais que normalmente processam grandes volumes de dados persistentes.

17.2 Hierarquia de Dados

Os menos dados que os computadores suportam são chamados bits. Bit é uma abreviatura de "binary digit".
Cada item de dados ou bit pode assumir o valor 0 ou o valor 1.

É complicado programar com dados na forma de baixo nível de bits. É preferível programar com dados em formas como dígitos decimais, letas, e símbolos especiais.

Os vários tipos de itens de dados processados pelos computadores formam uma hierarquia de dados na qual os itens de dados se tornam maiores e mais complexos na estrutura à medida que passamos de bits para caracteres, para campos e até estruturas de dados maiores.

Para facilitar a recuperação de registros específicos de um arquivo, pelo menos um campo em cada registro é escolhido como como chave de registro exclusiva.

Existem muitas maneiras de organizar os registros em um arquivo. O tipo mais comum de organização é chamado de arquivo sequencial, no qual os registro normalmente são armazenados em ordem pelo campo de chave do registro.

(Pode ser bom pesquisar mais sobre)

17.3 Arquivos e Fluxos

o C# vê cada arquivo com um fluxo (stream) sequencial de bytes. Cada arquivo termina com um marcador de final de arquivo ou em um número de byte específico, que é escrito em uma estrutura de dados administrativa mantida pelo sistema. Quando um arquivo é aberto, o C# cria uma objeto e, em seguida, associa um fluxo a esse objeto. O ambiente de tempo de execução cria três objetos fluxo na execução do programa, que são acessíveis por meio das propriedades Console.Out, Console.In e Console.Error, respectivamente. Esses objetos facilitam a comunicação entre um programa e um arquivo ou dispositivo em particular. A propriedade Console.In retorna o objeto fluxo de entra padrão, que permite ao programa fornecer dados a partir do teclado. A propriedade Console.Out retorna o objeto fluxo de saída padrão, que permite ao programa produzir saída de mensagens de dados na tela. A propriedade Console.Error retorna o objeto fluxo de error padrão, que permite ao programa produzir saída de mensagens de erro na tela.

O C# fornece a classe BinaryFormatter, que é usada em conjunto com um objeto Stream para realizar a entrada e a saída de objetos. A serialização envolve converter um objeto para um formato que possa ser gravado em um arquivo, sem perder quaisquer dados desse objeto. A desserialização consiste em ler esse formato de um arquivo e reconstruir o objeto original a partir dele. Um BinaryFormatter pode serializar e desserializar objetos em um Stream especificado.

A classe System.IO.Stream fornece funcionalidade para representar fluxos como bytes. Essa classe é abstract, de modo que seus objetos não podem ser instanciados. As classes FileStream, MemoryStream e BufferedStream herdam da classe Stream.

(Pode ser útil pesquisar mais sobre)

17.4 Classes File e Directory

A classe File é fornecida para manipular arquivos, e a classe Directory é fornecida para manipular diretórios.

Métodos da classe File (Lista parcial).

Métodos static Descrição
AppendText Retorna um objeto StreamWriter que anexa dados a um arquivo existente ou cria um arquivo para colocar os dados, se não existir nenhum.
Copy Copia um arquivo para um novo arquivo.
Create Cria um arquivo e retorna seu objeto FilesStream associado.
CreateText Cria um arquivo de texto e retorna seu objeto StreamWriter associado.
Delete Exclui o arquivo especificado.
GetCreationTime Retorna um objeto DateTime representando a hora em que o arquivo foi criado.
GetLastAccessTime Retorna um objeto DateTime representando a hora em que o arquivo foi acessado pela última vez.
GetLastWriteTime Retorna um objeto DateTime representando a hora em que o arquivo foi modificado pela última vez.
Move Move o arquivo especificado para uma posição especificada.
Open Retorna um objeto FileStream associado ao arquivo especificado e equipado com as permissões de leitura/gravação especificadas.
OpenRead Retorna um objeto FileStream somente de leitura associado ao arquivo especificado.
OpenText Retorna um objeto StreamReader associado ao arquivo especificado.
OpenWrite Retorna um objeto FileStream de leitura/gravação associado ao arquivo especificado.

Métodos da classe Directory (lista parcial).

Método static Descrição
CreateDirectory Cria um diretório e retorna seu objetivo DirectoryInfo associado.
Delete Exclui o diretório especificado.
Exists Retorna true se o diretório especificado existe
GetLastWriteTime Retorna um objeto DateTime representando a hora em que o diretório foi modificado pela última vez.
GetDirectories Retorna um array de strings representando os nomes dos subdiretórios no diretório especificado.
GetFiles Retorna um array de strings representando os nomes dos arquivos no diretório especificado.
GetCreationTime Retorna um objeto DateTime representando a hora em que o diretório foi criado.
GetLastAccessTime Retorna um objeto DateTime representando a hora em que o diretório foi acessado pela última vez.
GetLastWriteTime Retorna um objeto DateTime representando a hora em que itens foram gravados no diretório pela última vez.
Move Move o diretório especificado para uma posição especificada.
  • Fig. 17.05: FileTest.cs
    Usando as classes File e Directory.

Consideraremos agora outro exemplo que usa os recursos de manipulações de arquivos e diretórios do C#. A classe FileSearchForm usa classes File e Directory em conjunto com classes para executar expressões regulares, para relatar o número de arquivos de cada tipo de arquivo existente no caminho do diretório especificado.

  • Fig. 17.06: FileSearch.cs
    Usando expressões regulares para determinar tipos de arquivos.

17.5 Criando um Arquivo de Acesso Sequencial

O C# não impõe nenhuma estrutura para arquivos. Assim, noções como a de um "registro" não existem nos arquivos C#. Isso significa que o programador deve estruturar os arquivos para atender aos requisitos dos aplicativos. Nesse exemplo usamos texto e caracteres especiais para organizar nossa própria noção de "registro".

Os exemplos a seguir demonstram o processamento de arquivos em um aplicativo de manutenção de conta bancária. Esses programas têm interfaces com o usuário semelhantes; portanto, criamos a classe BankUIForm para encapsular uma GUI de classe base.

Para reutilizar a classe BankUIForm, compilamos a GUI em uma biblioteca de DLL, criando um projeto do tipo Windows Control Library.

O atributo Serializable indica para o compilador que os objetos da classe Record podem ser serializados ou representados como conjuntos de bytes. Os objetos que queremos ler ou escrever em um fluxo devem incluir esse atributo em suas definições de classe.

  • Fig. 17.07: BankUI.cs
    Um formulário Windows reutilizável para os exemplos deste capítulo.

  • Fig. 17.08: Record.cs
    Classe serializável que representa um registro de dados.

A classe CreateFileForm usa instâncias da classe Record para criar um arquivo de acesso sequencial, que pode ser usado em um sistema de contas a receber.

17.6 Lendo Dados de um Arquivo de Acesso Sequencial

Os dados são armazenados em arquivos, para que eles possam ser recuperados para processamento quando forem necessários. Nesta seção discutiremos como ler (ou recuperar) dados sequencialmente de um arquivo.

Agora apresentaremos um programa mais substancial.

  • Fig. 17.12: CreditInquiry.cs
    Lê um arquivo sequencialmente e exibe o conteúdo baseado no tipo de conta especificado pelo usuário (crédito, débito ou saldo zero).

17.7 Arquivos de Acesso Aleatório

Até aqui explicamos como criar arquivos de acesso sequencial e como pesquisar esses arquivos para localizar informações específicas. Entretanto, os arquivos de acesso sequencial são inadequados para os famosos aplicativos de "acesso instantâneo", nos quais um registro em particular de informação deve ser localizado imediatamente.

Os aplicativos de acessos instantâneo populares incluem sistemas de reservas aéreas, sistemas bancários, sistemas de ponto de venda, caixas automáticos e outros tipos de sistemas de processamento de transações que exigem rápido acesso a dados específicos. Um banco banco pode ter centenas de milhares ou mesmo milhões de clientes; entretanto, uma pessoa pode consultar seu saldo em um caixa eletrônico em questão de segundos.

Esse tipo de acesso instantâneo se dá por meio dos arquivos de acesso aleatório. Os registros individuais de um arquivo de acesso aleatório podem ser acessados direta e rapidamente sem que seja necessário pesquisar grandes números de outros registros, como acontece no caso dos arquivos de acessos sequencial. Às vezes os arquivos de acesso aleatório são chamados de arquivos de acesso direto.

Como vimos, o C# não impõe uma estrutura sobre arquivos; portanto os aplicativos que usam arquivos de acesso aleatório devem implementar o recurso de acesso aleatório. Existem muitas técnicas para criar arquivos de acesso aleatório. O uso de registros de tamanho fixo permite que um programa calcule a localização exata de qualquer registro em relação ao início do arquivo.

17.8 Criando um Arquivo de Acesso Aleatório

Considere a exposição de problema a seguir, de um aplicativo de processamento de crédito:

Crie uma programa de processamento de transações capaz d armazenar um máximo de 100 registros de tamanho fixo, para uma empresa que pode ter no máximo 100 clientes. Cada registro consiste em um número de conta (que atua como chave de registro), um sobrenome, um nome de batismo e um saldo. O programa pode atualizar uma conta, criar uma conta e excluir uma conta.

As próximas seções apresentarão as técnicas necessárias para criar esse tipo de programa de processamento de crédito.

17.9 Gravando Dados Aleatoriamente em um Arquivo de Acesso Aleatório

17.10 Lendo Dados Sequencialmente de um Arquivo de Acesso Aleatório

E quanto a vantagem adicional que prometemos? Se o leitor examinar a GUI quando o programa for executado notará que ele exibe os registros em ordem crescente pelo número da conta! Essa é uma consequência simples do uso de nossas técnicas de acesso direto para armazenar esses registros no arquivo.

17.11 Estudo de Caso: Um programa de processamento de transações

Desenvolvemos agora um programa de processamento considerável usando um arquivo de acesso aleatório para obter processamento de "acesso instantâneo". O programa mantém informações de conta de um banco.

Comportamento de processamento de transações

Neste estudo de caso, criamos a classe Transaction, que atua como um proxy ("agente") para manipular todo processamento de transações. Em vez de fornecer a funcionalidade necessária. Usando um proxy, podemos encapsular o comportamento de processamento de transações em apenas uma classe, permitindo que várias outras classes em nosso aplicativo reutilizem esse comportamento.