Programação Orientada à Procedimentos II Programação Orientada à Procedimentos I Processamento Paralelo Lógica de Programação Introdução à Computação Informática Básica

 

 

Informática Básica
Introdução à Computação
Lógica de Programação
Programação Orientada à Procedimentos I
Programação Orientada à Procedimentos II

Processamento Paralelo

Aula do dia 17 de Março

Aula do dia 24 de Março de 2003

Aula do dia 27 de Março



Arquivos em Disco


Formas de Acesso a Um Arquivo

- Acesso Sequencial
- Acesso Aleatório

Operações com Arquivos

- Arquivo Texto
- Arquivo Binário



Arquivos em Disco

Já foi estudado o conceito de tabelas em memória, através da utilização de matrizes. Estes conceitos já estudados são a base para a utilização de um arquivo. As matrizes são manipuladas através de um índice de controle enquanto os arquivos são manipulados por um ponteiro de registro. A principal vantagem na utilização de um arquivo está no fato de as informações armazenadas poderem ser utilizadas a qualquer momento. Outra vantagem encontrada na utilização de arquivos é o fato de poder armazenar um número maior de registros do que em uma tabela em memória, estando apenas limitado ao tamanho do meio físico utilizado para a sua gravação.
Um arquivo é um conjunto de registro (que poderá ser apenas um registro), que por sua vez é um conjunto de campos (que poderá ser apenas uma campo), sendo cada campo o conjunto de informações nele contido. As informações NOME, ENDEREÇO, TELEFONE, são exemplos de campos. Uma ficha de cadastro que contenha os campos para preenchimento será um registro.


Formas de Acesso a Um Arquivo

Os arquivos criados com a linguagem C poderão ser acessados para leitura e escrita de duas formas: seqüencial e aleatório .
Arquivo de Acesso Seqüencial: O acesso seqüencial ocorre quando o processo de gravação e leitura é feito de forma contínua, um após o outro a partir do primeiro registro, registro a registro, até localizar a primeira posição vazia após o último registro. O processo de leitura também ocorre de forma seqüencial. Se o registro a ser lido é o último, primeiro será necessário ler todos os registros que o antecedem. Este processo é considerado lento.
Arquivo de Acesso Aleatório: O acesso aleatório ocorre através da transferência de dados diretamente para qualquer posição do arquivo, sem que para isso, as informações anteriores precisem ser lidas (acesso seqüencial). O acesso aleatório a um arquivo pode ser feito de três formas diferentes, com relação ao posicionamento do ponteiro dentro do arquivo: início do arquivo, fim do arquivo ou o posicionamento atual do ponteiro no arquivo.


Operações com Arquivo

A manipulação de um arquivo em C ocorrerá com a definição do tipo FILE, o qual se caracteriza por ser uma estrutura formada por elementos do mesmo tipo dispostos de forma seqüencial, tendo como objetivo a finalidade de fazer a comunicação entre a memória principal (RAM) e memória secundária (meios magnéticos), através do programa e do sistema operacional. Assim sendo, este tipo deverá ser definido com a utilização da seguinte sintaxe:


FILE <*variável ponteiro> 

onde: <*variável ponteiro> - definição de um ponteiro para a estrutura do tipo FILE

O tipo FILE deverá ser escrito em caracteres maiúsculos, sendo esta uma estrutura cujos elementos são informações que assinalam a condição de processamento e acesso a um arquivo. Esta estrutura está presente na biblioteca stdio.h. Por esta razão, será necessário sempre indicar no programa a linha #include "stdio.h", antes da função main ().
Para manipular um arquivo (ler ou escrever) é necessário executar duas operações básicas: abertura e fechamento, sendo conseguidas com a utilização das instruções: fopen () e fclose (), desde que o arquivo exista.
Para efetuar as operações de leitura e escrita de um arquivo, este deverá ser aberto e depois de utilizado, o arquivo precisa ser fechado. Para a abertura de um arquivo deverá ser utilizada em um programa, a seguinte linha de código:


 variável ponteiro = fopen ("nome do arquivo", "tipo de abertura");

onde: variável ponteiro - é a variável declarada como ponteiro do tipo FILE
nome do arquivo - é o nome do arquivo a ser manipulado
tipo de abertura - o tipo de abertura do arquivo (ver tabela a seguir)

Para o fechamento de um arquivo deverá ser utilizada em um programa, a seguinte linha de código:


fclose (variável ponteiro);

onde: variável ponteiro - é a mesma variável associada à função fopen ()

O tipo de abertura de um arquivo é especificado por três códigos do tipo string, a saber: letra r - para leitura (read), letra w - para gravação (write) e letra a para adicionar dados (append). A seguir, é apresentada uma tabela com todas as combinações possíveis.


Tipo de AberturaDescrição
rEste código permite apenas abrir um arquivo do tipo texto para leitura de seus dados. É necessário que o arquivo esteja presente no disco.
wEste código permite apenas abrir um arquivo do tipo texto para escrita (gravação). Este código cria o arquivo para ser trabalhado. Caso o arquivo exista, este código fará a recriação do arquivo, ou seja, você perderá o arquivo criado anteriormente. Deve ser usado com muito cuidado.
aEste código permite apenas abrir um arquivo do tipo texto para escrita (gravação), permitindo acrescentar novos dados ao final do mesmo. Caso o arquivo não exista, este será então criado.


Arquivo Texto: Este tipo de arquivo permite possuir registros armazenados com tamanhos diferentes (o que não ocorre com os outros tipos de arquivo). Se você direcionar o prompt do DOS para o diretório TC, terá como exemplo de um arquivo texto o arquivo THELP.DOC que poderá ser visualizado com o comando DOS: type thelp.doc. Os arquivos do tipo texto estão capacitados a armazenar caracteres, palavras, frases e também dados numéricos. Os números, entretanto, serão armazenados como caracteres do tipo alfanumérico, e desta forma ocuparão muito mais espaço em disco do que ocupariam na memória de um computador. A solução para este detalhe é utilizar funções que manipulem os números em formato binário, o que será visto mais adiante.

1º Exemplo - Antes de iniciar qualquer operação com arquivo, é necessário criá-lo. Para tanto, digite o programa abaixo e grave-o com o nome ARQTXT01.



/* Criacao de arquivo texto */

# include "stdio.h";
main()
{
     FILE *PTRARQ;     /* definicao do ponteiro para o arquivo */ 
     PTRARQ = fopen ("ARQTXT0l.XXX", "a");
     fclose (PTRARQ);
}

Após digitar o programa, grave-o com o nome ARQTXT01, e depois de rodá-lo com o comando Run/Run, execute o comando File/OS shell para visualizar o prompt do DOS. Em seguida execute o comando DOS: dir arqtxt01.xxx, e você verá a apresentação do arquivo arqtxt01.xxx criado com zero bytes. Para voltar ao Turbo C, execute o comando DOS: exit.
O programa acima estabelece para a variável ponteiro PTRARQ o tipo FILE, em seguida a variável ponteiro é igualada à função fopen ("ARQTXT01.XXX", "a");, que tem por finalidade definir o tipo de arquivo texto. Observe a utilização da string "a" que efetua a criação do arquivo, caso este não exista. Por fim, é utilizada a função fclose(PTRARQ);, que efetua o fechamento do arquivo criado. Tendo um arquivo criado, este poderá ser agora utilizado para a gravação das informações que irá guardar. Digite o programa abaixo e grave-o com o nome ARQTXT02.


/* Grava palavra no arquivo texto */

#include "stdio.h";
main ()
{
     FILE *PTRARQ;
     char PALAVRA [20];
     PTRARQ = fopen ("ARQTXT01.XXX", "w");
     scanf ("%s", &PALAVRA);
     fprintf (PTRARQ, "%s", PALAVRA);
     fclose (PTRARQ);
}

Após rodar o programa, execute novamente o comando File/OS Shell para visualizar o prompt do DOS. Peça o comando DOS: dir *.xxx, e você verá a apresentação do arquivo arqtxt01.xxx com um número de bytes. Não se esqueça de voltar para o Turbo C.
O programa acima estabelece uma variável PALAVRA do tipo char com a capacidade de armazenar até 20 caracteres. As demais instruções já são conhecidas, com exceção da linha com a função fprintf (), que é semelhante à função printf (), tendo como diferença o primeiro argumento, que é a indicação da variável ponteiro e que faz a saída da informação para o arquivo em disco e não para o vídeo.

A seguir, é apresentado um programa que irá efetuar a leitura de um arquivo texto, mostrando no vídeo a informação armazenada com o programa anterior. Digite o programa abaixo e grave-o com o nome ARQTXT03.


/* Leitura de um arquivo texto */

#include "stdio.h"; 
main ()
{
     FILE *PTRARQ; 
     char PALAVRA [20];
     PTRARQ = fopen ("ARQTXT01.XXX", "r"); 
     fscanf (PTRARQ, "%s", PALAVRA); 
     printf ( "%s", PALAVRA);
     fclose (PTRARQ);
}

A instrução fscanf (PTRARQ, "%s", PALAVRA); faz a leitura do registro no arquivo, transferindo a informação lida para a variável PALAVRA que será apresentada no vídeo pela instrução printf ();. Observe que para efetuar a leitura, a função fopen() está fazendo uso da string "r".

2º Exemplo - Tendo um conhecimento básico sobre arquivos, será visto como gravar uma palavra ou frase caractere a caractere. Este segundo exemplo é diferente do primeiro que efetuou apenas a gravação de uma palavra, pois, no primeiro exemplo, se você tentar digitar uma frase, só conseguirá gravar a primeira palavra da frase.

O programa a seguir fará a criação e também a gravação da frase que será digitada e encerrada com a utilização da tecla ENTER.


/* Cria e grava frase caractere a caractere */

#include "stdio.h"; 
main ()
{
     FILE *PTRARQ; 
     char LETRA; 
     PTRARQ = fopen ("FRASE.XXX" , "w"); 
     while ((LETRA = getche ()) != '\r')
          putc (LETRA, PTRARQ);
     fclose (PTRARQ);
}

Após digitar o programa, grave-o com o nome ARQTXT04, e depois de rodá-lo com o comando Run/Run, digite a frase desejada, e após fazer uso da tecla ENTER para finalizar a digitação, execute o comando File/OS shell para visualizar o prompt do DOS. Em seguida execute o comando DOS: type frase.xxx, para verificar a existência da frase digitada. Para voltar ao Turbo C, lembre-se de executar o comando DOS: exit.

Observe que o segundo exemplo em relação ao primeiro apresenta uma mobilidade maior de trabalho, pois permitiu que fosse gravada uma frase.Note no programa, o uso da instrução putc (LETRA, PTRARQ);, que tem por finalidade efetuar apenas a captura de um caractere digitado no teclado e colocá-lo na variável LETRA através da referência feita no ponteiro PTRARQ, enquanto o caractere digitado seja diferente da tecla ENTER, que no caso está sendo verificado pela instrução while((LETRA = getche ()) != "\r").

Vejamos como fazer a apresentação do conteúdo do arquivo através de um programa em C que fará a leitura caractere a caractere.


/* Le frase caractere a caractere */

#include "stdio.h";
main ()
{
     FILE *PTRARQ; 
     char LETRA;
     PTRARQ = fopen ("FRASE.XXX", "r");
     while ((LETRA = getc (PTRARQ)) != EOF)
          printf ("%c", LETRA);
     fclose (PTRARQ);
}

Após digitar o programa, grave-o com o nome ARQTXT05, e depois de rodá-lo com o comando Run/Run, utilize as teclas ALT + F5 para visualizar a apresentação da frase armazenada no arquivo. Note que o programa está fazendo uso da função getc () para efetuar a leitura de apenas um caractere armazenado, o qual é apresentado no vídeo pela função printf (), enquanto não for encontrado o fim de arquivo (EOF - End Of File).
Em C, o EOF não é um caractere de controle de fim de arquivo, mas um valor inteiro enviado ao programa através do MS-DOS, valor este representado no arquivo stdio.h como sendo -1. Dependendo do sistema operacional, este valor poderá ser diferente.
No exemplo anterior, o fim de arquivo está sendo comparado com uma variável do tipo char. Neste caso, EOF está sendo interpretado como sendo um valor diferente do código ASCII 255.
Uma outra forma de identificar o fim de arquivo é fazendo uso da função feof (), que possui como parâmetro o ponteiro de arquivo. A seguir, é apresentado o programa ARQTXT05 utilizando a função indicada.


/* Le frase caractere a caractere com feof() */

#include "stdio.h"
main ()
{
     FILE *PTRARQ; 
     char LETRA;
     PTRARQ = fopen ("FRASE.XXX", "r");
     while (!feof (PTRARQ))
        {
             LETRA = getc (PTRARQ);
             printf ("%c", LETRA);
        }
     fclose (PTRARQ);
}

O programa irá processar a leitura do arquivo caractere a caractere, enquanto não for fim de arquivo. A função feof () retorna o valor verdadeiro caso o final de arquivo tenha sido alcançado; caso contrário, será devolvido o valor 0 (zero). Após a digitação do programa, grave-o com o nome de ARQTXT5A.

3º Exemplo - Tendo anteriormente sido feita uma seqüência de programa que manipulou palavras inteiras e também manipulou caractere por caractere, será dado um exemplo que aceitará uma string como um todo, pois tanto a leitura quanto a escrita de uma string inteira em um arquivo são mais fáceis do que efetuar as operações caractere a caractere.

O programa a seguir fará a criação e a gravação de frases em um arquivo, sendo semelhante ao programa de gravação de palavras, mas com um detalhe diferente, pois a gravação será efetuada linha a linha.


 /* Cria e grava frases */

#include "stdio.h"
main ()
{
     FILE *PTRARQ;
     char RESP, FRASE [81];
     RESP='S';
     PTRARQ = fopen ("FRASE2.XXX", "w"); 
     while (RESP == 'S' || RESP == 's')
        {
             clrscr ();
             printf ("\nDigite uma frase qualquer\n\n"); 
             gets (FRASE); 
             fputs (FRASE, PTRARQ); 
             fputs ("\n", PTRARQ); 
             printf ("\nDeseja continuar (S/N)? "); 
             scanf ("%c", &RESP); 
             fflush (stdin);
        }
     fclose (PTRARQ);
} 

Após ter digitado o programa, grave-o com o nome ARQTXT06. Observe no programa, a instrução while (RESP == 'S' II RESP == 's'), a qual fará a gravação enquanto o usuário desejar. A função gets () espera a string a ser digitada, a qual é encerrada com o pressionamento da tecla ENTER, em seguida, o programa possui duas funções puts (), sendo a primeira responsável por gravar no arquivo a string digitada e a segunda por gravar o caractere "\n", que corresponde ao caractere de nova linha. Desta forma, é possível o arquivo possuir várias frases armazenadas, uma após a outra.

A seguir, é apresentado um programa que fará a leitura do arquivo FRASE2.XXX criado anteriormente.


  /* Apresenta frases */

#include "stdio.h"
main ()
{
     FILE *PTRARQ;
     char FRASE [81];
     PTRARQ = fopen ("FRASE2.XXX", "r");
     while (fgets (FRASE, 80, PTRARQ) != NULL)
          printf ("%s", FRASE);
     fclose (PTRARQ);
} 

Digite e grave o programa com o nome ARQTXT07. Note neste exemplo, o uso da função fgets (), a qual possui três argumentos. O primeiro argumento representa o ponteiro que indica o buffer onde está a linha lida. O segundo argumento representa o tamanho máximo de caracteres a ser lido, sendo que este valor deverá ser um a mais que o tamanho de uma string, devido à existência do caractere NULL no final de cada string; caractere este que é colocado pela função gets () e é representado pelo código '\0'. O terceiro argumento é o ponteiro FILE. A função fgets () termina a sua leitura quando encontra o caractere de nova linha '\n' no final de cada frase, ou quando encontra o caractere de fim de arquivo EOF.
Vamos aproveitar o exemplo anterior para fazer uso da função feof () na identificação do final de arquivo.


 /* Apresenta frases */

#include "stdio.h"
main ()
{
     FILE *PTRARQ;
     char FRASE [81];
     PTRARQ = fopen ("FRASE2.XXX", "r"); 
     while (!feof (PTRARQ))
        {
             fgets (FRASE, 80, PTRARQ);
             printf ("%s", FRASE);
        }
     fclose (PTRARQ);
} 

O programa irá processar a leitura do arquivo de cada frase existente enquanto não for fim de arquivo. Após a digitação do programa, grave-o com o nome de ARQTXT7A.

4º Exemplo - Para exemplificar a utilização de arquivo do tipo texto, considere um pequeno programa que deverá solicitar e armazenar nomes de pessoas. Este programa deverá ter um menu contendo quatro opções: criar arquivo, cadastrar registro, exibir registros cadastrados e finalizar o programa. Para tanto, observe o algoritmo a seguir:

Programa Principal
1. Definir as variáveis de controle e abertura do arquivo.
2. Apresentar um menu de seleção com quatro opções:

  • Criar arquivo
  • Cadastrar registro
  • Exibir registros
  • Fim de Programa
3. Ao ser selecionado um valor, a rotina correspondente deverá ser executada.
4. Ao se escolher o valor 4, encerrar o programa.

Rotina 1 - Criar arquivo
1. Executar o comando de criação de um arquivo;
2. Fechar o arquivo;
3. Voltar ao programa principal.

Rotina 2 - Cadastrar
1. Abrir o arquivo para cadastramento;
2. Ler o nome;
3. Escrever o nome no arquivo;
4. Fechar o arquivo;
5. Voltar ao programa principal.

Rotina 3 - Exibir
1. Abrir o arquivo para leitura;
2. Apresentar os dados do arquivo enquanto não for encontrado o último registro;
3. Fechar o arquivo;
4. Voltar ao programa principal.

Apesar de simples, o programa dará uma boa visão, pois será necessário trabalhar com alguns novos recursos. Digite o programa a seguir, e grave-o com o nome NOMESTXT.


/* Programa: Nomes em um arquivo texto */
#include "stdio.h"
#include "conio.h"

void criar();
void cadastrar();
void exibir();

char NOME[41], TECLA;
FILE *PTRARQ;

void main( )
{
 	int OPCAO;
	while (OPCAO !=4)
	{
	   clrscr();
	   gotoxy(33, 1); printf("Menu Principal");
	   gotoxy(33, 2); printf(" ------------------");
	   gotoxy(29, 5); printf("1 ..................Cria arquivo");
	   gotoxy(29, 6); printf("2 ......... Cadastra registro");
	   gotoxy(29, 7); printf("3..............Exibe registros");
	   gotoxy(29, 8); printf("4................................Fim");
	   gotoxy(29,11); printf("Escolha a sua opcao: ");
	   scanf("%d", &OPCAO); 
     if (OPCAO !=4)
     {
        switch (OPCAO)
        {
          case	1:	criar();
                    break;
          case	2:  cadastrar();
                    break;
          case	3:  exibir();
                    break;
          default:  printf("Opcao invalidade - Tente novamente");
                    TECLA = getche ( );
        }
    }
  }
}

void criar()
{
      clrscr();
      gotoxy(31,1); printf("Criacao de Arquivo");
      PTRARQ = fopen("NOMESTXT.DAT", "w");
      gotoxy(31,12); printf("Arquivo foi criado");
      gotoxy(25,24); printf("Tecle algo para voltar ao menu"); 
      TECLA = getche();
      fclose(PTRARQ);
}	

void cadastrar()
{
      clrscr ( );
      gotoxy(27, 1); printf("Cadastramento de Registro");
      PTRARQ = fopen("NOMESTXT.DAT", "a");
      gotoxy(10, 5); printf("Entre o Nome");
      fflush(stdin); gets(NOME);
      fputs (NOME, PTRARQ);
      fputs("\n", PTRARQ);
      gotoxy(25,24); printf("Tecle algo para voltar ao menu");
      TECLA = getche( );
      fclose(PTRARQ);
}

void exibir()
{
      int LINHA=5;
      clrscr();
      gotoxy(27, 1); printf("Apresentacao de Registros");
      PTRARQ = fopen("NOMESTXT.DAT", "r");
      while (fgets(NOME, 40, PTRARQ) != NULL)
      {
          gotoxy( 5,LINHA); printf (" %s", NOME);
          LINHA += 1;
      }
      gotoxy(25,24); printf("Tecle algo para voltar ao menu");
      TECLA = getche();
      fclose (PTRARQ);
}

Ao fazer uso do programa, procure cadastrar poucos registros (ideal em torno de 15), pois não está sendo previsto exibir uma quantidade muito grande de dados na tela. Primeiro execute a criação do arquivo, faça alguns cadastramentos e encerre o programa. Saia do Turbo C. Depois volte, chame o programa e peça para visualizar os dados cadastrados. Cadastre mais alguns e visualize novamente. Depois de cadastrar alguns registros, se for solicitado efetuar a criação do arquivo novamente, este será recriado, destruindo os dados já cadastrados.

Arquivo Binário: Nada impede de que sejam armazenados números em arquivos do tipo texto, porém deve-se levar em consideração que um número gravado como um caractere alfanumérico ocupa um espaço maior do que se for armazenado como sendo do tipo binário.
A seguir, serão apresentadas duas rotinas que exemplificarão o uso de arquivos com matrizes de uma dimensão, as quais farão a manipulação dos arquivos, considerando-os do tipo binário. Um arquivo do tipo binário é indicado pela forma de acesso utilizado pela instrução fopen("MATINT.DBC", "wb"), onde wb é a indicação de escrita de um arquivo binário.
A primeira rotina deverá solicitar a entrada de dez valores inteiros, e armazenar os valores em uma matriz para transferi-los de uma só vez a um arquivo. Depois deverá ser escrita uma segunda rotina que leia os dados do arquivo, transferindo-os para uma matriz, para então apresentá-los. Os programas em questão irão tratar os arquivos como sendo binários.
Digite o programa a seguir e grave-o com o nome MATINT01. Observe que será criado um arquivo chamado MATINT.DBC que conterá dez valores inteiros. Perceba que assim que os elementos são fornecidos para a matriz A, estes são em seguida gravados no arquivo de uma só vez com a instrução fwrite( ). Nada impede de se utilizar a função fprintf() para gravar os dados no arquivo, porém deve-se levar em conta que esta função irá gravar um registro por vez.


/* Matriz com Arquivo */
#include "stdio.h"
#include "conio.h"

main()
{
    int I, A[10];
    FILE *PTRARQ;
    PTRARQ = fopen("MATINT.DBC", "wb");
    clrscr();
    I = 0;
    while (I <10)
    {
       printf("Digite o elemento - %2d: ", I+1);
       scanf("%d", &A[I]);
       I += 1;
    }
    fwrite(A, sizeof(A), 1, PTRARQ);
    fclose(PTRARQ);
}

Observe no programa, a utilização da função fwrite() fora do looping, sendo que a mesma tem a finalidade de efetuar a escrita de dados maiores que um byte. Note que esta função faz uso de quatro argumentos, obedecendo à seguinte sintaxe:

fwrite(buffer, tamanho, contador, ponteiro);

onde:
buffer - endereço da área de memória com os dados a serem gravados;
tamanho - tamanho do item a ser gravado;
contador - especifica o número de itens a ser gravado;
variável - é a variável do tipo ponteiro de arquivo.

Digite o programa a seguir e grave-o com o nome MATINT02. Observe que o programa fará a abertura e a leitura do arquivo MATINT.DBO que contém dez valores inteiros, que serão armazenados na memória, depois apresentará os valores armazenados.


#include "stdio.h"

main( )
{
    int I, A[l0];
    FILE *PTRARQ;
    PTRARQ = fopen( "MATINT.DBC", "rb");
    clrscr ();
    fread(A, sizeof(A), 1, PTRARQ);
    I = 0;
    while (I <10)
    {
       printf("\n O elemento %2d equivale a %2d: ", I + 1, A[I]);
       I += 1;
    }
    fclose (PTRARQ);
}

A função fread() é idêntica à função fwrite(), tendo como diferença a possibilidade de efetuar a leitura de uma só vez de todos os dados de um arquivo e transferi-los para a memória. Uma das maiores aplicações das funções fread() e fwrite() é o fato de elas serem usadas para ler e escrever tipos de dados definidos pelo programador, como é o caso das estruturas (struct).