 |
Aula
do dia 24 de Março de 2003 |
|
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 Abertura | Descrição |
r | Este código permite apenas abrir um arquivo do tipo texto para
leitura de seus dados. É necessário que o arquivo esteja presente no disco. |
w | Este 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. |
a | Este 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).
|