Você está na página 1de 11

1

IMES – Centro Universitário São Caetano do Sul - CIÊNCIA DA COMPUTAÇÃO - 2º ANO –


ESTRUTURAS DE DADOS - Prof. Edson Pinheiro Pimentel

ARQUIVOS EM C

Existem dois conjuntos de funções de E/S com arquivos na linguagem C. Num primeiro ponto, tem-se a
E/S ANSI (com buffer ou formatada) e, em termos mais específicos, tem-se a E/S UNIX (sem buffer ou
não formatada). Uma ênfase maior é dada ao primeiro conjunto pela portabilidade deste sistema de
entrada e saída com arquivos.
Existem dois tipos possíveis de acesso a arquivos na linguagem C : sequencial (lendo um registro após o
outro) e aleatório (posicionando-se diretamente num determinado registro).
O sistema de arquivos na linguagem C é definido para manipular uma série de dispositivos, tais como
terminais, acionadores de disco e outros. Estes dispositivos são vistos como arquivos lógicos em C,
denominados STREAM (abstração do dispositivo). O dispositivo real é denominado ARQUIVO
(impressora, disco, console e outros). Um STREAM é associado a um ARQUIVO por uma operação de
abertura do arquivo e, a partir da associação, todas as demais operações de escrita e leitura podem ser
realizadas. A Tabela 1 apresenta as principais funções da linguagem C para manipulação de arquivos.

Função Ação
fopen() Abre um arquivo
Fclose () Fecha um arquivo
putc() e fputc() Escreve um caractere em um arquivo
getc() e fgetc() Lê um caractere de um arquivo
fseek() Posiciona em um registro de um arquivo
fprintf() Efetua impressão formatada em um arquivo
fscanf() Efetua leitura formatada em um arquivo
feof() Verifica o final de um arquivo
fwrite() Escreve tipos maiores que 1 byte em um arquivo
fread() Lê tipos maiores que 1 byte de um arquivo

Tabela 1 - Funções do padrão ANSI para manipulação de arquivos

O sistema de entrada e saída do ANSI C é composto por uma série de funções, cujos protótipos estão reunidos em stdio.h .
Todas estas funções trabalham com o conceito de "ponteiro de arquivo". Este não é um tipo propriamente dito, mas uma
definição usando o comando typedef. Esta definição também está no arquivo stdio.h. Podemos declarar um ponteiro de
arquivo da seguinte maneira:

FILE *Arquivo;

Pela declaração anterior, passa a existir uma variável de nome Arquivo, que é ponteiro para um
arquivo. O ponteiro de arquivo une o sistema de E/S a um buffer. O ponteiro não aponta diretamente
para o arquivo em disco, mas contém informações sobre o arquivo, incluindo nome, status (aberto,
fechado e outros) e posição atual sobre o arquivo.
2
1) ABRINDO UM ARQUIVO

A função que abre um arquivo em C é a função fopen(), que devolve o valor NULL (nulo) ou um
ponteiro associado ao arquivo, devendo ser passado para função o nome físico do arquivo e o modo
como este arquivo deve ser aberto. Arquivo = fopen ("texto.txt","w");

Com a instrução acima, está sendo aberto um arquivo de nome "texto.txt", no disco, habilitado
apenas para escrita (w-write). Utilizando-se técnicas de verificação, pode-se codificar a instrução
acima da seguinte maneira:
if ((Arquivo = fopen("texto.txt","w")) == NULL) {
printf("\n Arquivo TEXTO.TXT não pode ser aberto : TECLE ALGO");
getch();
}

Além do modo de escrita, a linguagem C permite o uso de alguns valores padronizados para o modo de
manipulação de arquivos, conforme mostra a Tabela 2

Modo Significado
"r" Abre um arquivo texto para leitura. O arquivo deve existir antes de ser aberto.
Abrir um arquivo texto para gravação. Se o arquivo não existir, ele será criado. Se já existir, o
"w"
conteúdo anterior será destruído.
Abrir um arquivo texto para gravação. Os dados serão adicionados no fim do arquivo ("append"), se
"a"
ele já existir, ou um novo arquivo será criado, no caso de arquivo não existente anteriormente.
"rb" Abre um arquivo binário para leitura. Igual ao modo "r" anterior, só que o arquivo é binário.
"wb" Cria um arquivo binário para escrita, como no modo "w" anterior, só que o arquivo é binário.
"ab" Acrescenta dados binários no fim do arquivo, como no modo "a" anterior, só que o arquivo é binário.
"r+" Abre um arquivo texto para leitura e gravação. O arquivo deve existir e pode ser modificado.
Cria um arquivo texto para leitura e gravação. Se o arquivo existir, o conteúdo anterior será destruído.
"w+"
Se não existir, será criado.
Abre um arquivo texto para gravação e leitura. Os dados serão adicionados no fim do arquivo se ele já
"a+"
existir, ou um novo arquivo será criado, no caso de arquivo não existente anteriormente.
"r+b" Abre um arquivo binário para leitura e escrita. O mesmo que "r+" acima, só que o arquivo é binário.
"w+b" Cria um arquivo binário para leitura e escrita. O mesmo que "w+" acima, só que o arquivo é binário.
Acrescenta dados ou cria uma arquivo binário para leitura e escrita. O mesmo que "a+" acima, só que
"a+b"
o arquivo é binário

Tabela 2 - Modos para manipulação de arquivos

MODO BINÁRIO X MODO TEXTO

Em modo texto, cada caracter (digito, letra, ou caracter especial) ocupa um byte. Ou seja, para gravar o
número 32153, que em memória ocuparia 2 bytes, em arquivo modo texto são necessários 5 bytes. O
modo binário é mais eficiente para guardar números pois ocupa menos espaço.

2) FECHANDO UM ARQUIVO

Para o esvaziamento do buffer de um arquivo é utilizada a função fclose(), que associa-se


diretamente ao nome lógico do arquivo (STREAM).
fclose (Arquivo);
3

3) GRAVANDO DADOS DADOS EM ARQUIVOS:

Existem várias funções em C para a operação de gravação de dados em Arquivos. Vejamos Algumas :
a) putc ou fputc: Grava um único caracter no arquivo
b) fprintf : Grava dados formatados no arquivo, de acordo com o tipo de dados (float, int, ...). Similar
ao printf, porém ao invés de imprimir na tela, grava em arquivo
c) fwrite : Grava um conjunto de dados heterogêneos (struct) no arquivo.

SINTAXE DO PUTC:

putc (caracter, arquivo); /* Grava o conteúdo da variável caracter no "arquivo" */

Vejamos o exemplo de putc, num programa que simula um editor de texto, bem simples, que grava em
arquivo um texto que vai sendo digitado via teclado até que o usuário finalize com um CTRL+Z

#include <stdio.h>
#include <conio.h>
void main () {
FILE *Arquivo;
char Caractere, Nome[20];
clrscr();
printf("Nome do arquivo? ");
fflush(stdin);
gets(Nome);
Arquivo = fopen (Nome,"w");
if (Arquivo == NULL) {
printf ("Erro abertura do Arquivo : %s. Tecle algo !\n",Nome);
getch();
}
else {
do {
Caractere = getche();
if (Caractere == 13) { \* teclou enter *\
putc('\n',Arquivo); \* grava um \n no arquivo
printf("\n"); \* pular linha na tela pois getche não faz isso com enter */
}
else {
putc(Caractere,Arquivo);
}
} while (Caractere != 26); // CTRL + Z para encerrar
}
fclose(Arquivo);
printf("\n Fim da digitação do texto !" );
getch();
}
Programa 1 – Manipulação de arquivo-texto para escrita

OBS : Mais adiante veremos a sintaxe e o exemplo de uso de fprintf e fwrite


4
4) LENDO DADOS EM ARQUIVOS:
Existem várias funções em C para a operação de leitura de dados de Arquivos. Vejamos Algumas :
a) getc ou fgetc: Lê um único caracter do arquivo
b) fscanf : Lê dados formatados no arquivo, de acordo com o tipo de dados (float, int, ...).
Similar ao scanf, porém ao invés de ler do "teclado" lê de um arquivo
c) fread : Lê um conjunto de dados heterogêneos (struct) do arquivo.

SINTAXE DO GETC:

Caracter = getc (arquivo); /* Lê um caracter do "arquivo" e retorna para a variável Caracter */

getc retorna EOF caso encontre o fim-de-arquivo ou em caso de erro na leitura

Vejamos o exemplo de getc, num programa que simula um "mostrador" de texto, bem simples, que lê
arquivo texto já gravado em disco e vai mostrando na tela :

#include <stdio.h>
#include <conio.h>
void main () {
FILE *Arquivo;
char Nome[20];
char Caractere;
clrscr ();
printf ("Nome do arquivo? ");
fflush(stdin);
gets (Nome);

Arquivo = fopen (Nome,"r");


if (Arquivo == NULL) {
printf ("Erro abertura do Arquivo : %s. Tecle algo !\n",Nome);
getch();
}
else {
Caractere = getc(Arquivo);
while (Caractere != EOF) {
printf("%c", Caractere);
Caractere = getc(Arquivo);
}
fclose (Arquivo);
printf("\n *** fim de texto *** Tecle algo !");
getch ();
}
}
Programa 2 – Manipulação de arquivo-texto para leitura

OBS : Mais adiante veremos a sintaxe e o exemplo de uso de fscanf e fread

EXERCICIOS :

a) Escreva um programa que faça a cópia de um arquivo origem, gerando um para um arquivo destino
onde todos os caracteres estejam em minúsculo. A função tolower converte um caracter para
minúsculo, está na biblioteca ctype.h e possui a seguinte sintaxe :
a = tolower(b);
A instrução acima converte o caracter da variável b para minúsculo e retorna para a variável a,
onde a e b podem ser a mesma variável.
5
b) Escreva um programa para contar quantas palavras existem num arquivo texto. Lembre-se de
considerar como separador de palavra os caracteres :
'\t' - caracter de tabulação
'\n' – quebra de linha
' ' - espaço em branco

AS OUTRAS FUNÇÕES DE LEITURA E GRAVAÇÃO EM ARQUIVO

A) LENDO E GRAVANDO DADOS "FORMATADOS" com fscanf e fprintf

Sintaxe :
• int fprintf(arquivo, "formatos", var1, var2 ...);
fprintf retorna a quantidade de bytes gravadas ou EOF em caso de
erro

No exemplo abaixo, suponha que arqfunc foi aberto com fopen ...
...
FILE *arqfunc;
int idade = 21, tot_bytes;
char sexo = 'M';
float salario = 552.75;
...
tot_bytes = fprintf (arqfunc, "%d %c %f ", idade, sexo,
salario);

obs. : Os formatos devem ser separados por espaços em branco

• int fscanf(arquivo, "formatos", &var1, &var2 ...);


fscanf retorna a quantidade variáveis lidas com sucesso

No exemplo abaixo, suponha que arqfunc foi aberto com fopen ...
...
FILE *arqfunc;
int idade = 21, totbytes;
char sexo = 'M';
float salario = 552.75;
...
quant_var = fscanf (arqfunc, "%d %c %f ", &idade, &sexo,
*salario);

obs. : Os formatos devem ser separados por espaços em branco

OBS : O uso de fscanf não é recomendada para string pois, da mesma


forma que scanf com %s, fscanf também encerra e leitura ao encontrar um
espaço em branco. Em outras palavras, se no arquivo estiver gravado um
nome "JOSE DA SILVA SOUZA" o fscanf lerá apenas para o formato %s a
palavra "JOSE". Como alternativa poderíamos usar a função fgets, mas esta
6
exige que se saiba a quantidade de caracteres a ser lido a cada momento.
Resolveremos este problema com fread e fwrite.

De qualquer forma, vejamos exemplos de programas com o uso de fprintf e


fscanf

O programa abaixo, obtém o Código do Funcionário, o sexo, a idade e o


salário de N pessoas, a partir do teclado, e grava os dados num arquivo,
utilizando fprintf

• O Critério de terminação é quando o usuário digita um código do


funcionário negativo
• Por questões de simplificação não estamos verificando se o arquivo
foi aberto com sucesso, nem se o sexo é válido ou não ...

/* programa exemplo com fprintf */

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
FILE *arqfunc;
int sexo;
int codfunc, idade;
float salario;

arqfunc = fopen("FUNCIONA.DAD", "w");

if (arqfunc == NULL) {
printf("\nArquivo FUNCIONA.DAD nao pode ser criado.");
printf("\nErro Grave ! Tecle algo !");
getch();
}
else {
clrscr();
do {
printf("\n Digite o codigo do funcionario ou um numero negativo \
para encerrar : ");
scanf("%d", &codfunc);
if (codfunc > 0){
printf("\n Digite o sexo [M ou F] : ");
sexo = getche();

printf("\n Digite a idade : ");


scanf("%d", &idade);
printf("\n Digite o salario : ");
scanf("%f", &salario);
/* a instrucao abaixo grava os dados no arquivo */
fprintf(arqfunc, "%d %c %d %f ", codfunc, sexo, idade, salario);
}
} while ( codfunc > 0);
fclose (arqfunc);
}
}

O programa abaixo lê o arquivo gravado com o programa


anterior, utilizando fscanf e mostra os dados na tela
7
• Veja que deve-se usar a mesma seqüência de leitura que
se usou para gravar : O Primeiro nome, depois o sexo, a idade e
o salário.
• Veja ainda que o nome é lido com fgets devido ao
problema já exposto anteriormente sobre o fscanf com %s
8

/* programa exemplo com fscanf

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define LETRAS 60

void main() {
FILE *arqfunc;
char sexo, aux;
int codfunc, idade, i = 0;
float salario;

clrscr();
arqfunc = fopen("FUNCIONA.DAD", "r");

if (arqfunc == NULL) {
printf("\nArquivo FUNCIONA.DAD nao pode ser aberto.");
printf("\nErro Grave ! Tecle algo !");
getch();
}
else {
aux = fscanf(arqfunc, "%d %c %d %f",&codfunc, &sexo, &idade, &salario);
while (aux != EOF) {
i = i + 1;
printf("\n Dados do %d § funcionario : \n ", i);
printf("\n Codigo : %d Sexo : %c", codfunc, sexo);
printf("\n Idade ...: %d Salario : %8.2f", idade, salario);
printf("\n------------------------------------- Tecle algo !");
getch();
aux = fscanf(arqfunc, "%d %c %d %f",&codfunc, &sexo, &idade, &salario);
}

fclose (arqfunc);
printf("\n *** FIM : Tecle algo ! ");
getch();
}
}

B) LENDO E GRAVANDO ESTRUTURAS

Além da manipulação de arquivos do tipo texto, pode-se ler e escrever estruturas maiores que 1 byte,
usando as funções fread() e fwrite(), conforme os protótipos seguintes.

fread (buffer, tamanhoembytes, quantidade, ponteirodearquivo)


fwrite (buffer, tamanhoembytes, quantidade, ponteirodearquivo)

O buffer é um endereço de memória da estrutura de onde deve ser lido ou onde devem ser escritos os
valores (fread() e fwrite(), respectivamente). O tamanhoembytes é um valor numérico
que define o número de bytes da estrutura que deve ser lida/escrita. A quantidade é o número de
estruturas que devem ser lidas ou escritas em cada processo de fread ou fwrite. O
ponteirodearquivo é o ponteiro do arquivo de onde deve ser lida ou escrita uma estrutura.

Normalmente quando trabalhos com arquivos (não texto), utilizamos arquivos de estruturas (struct).
Podemos por exemplo falar num arquivo de CLIENTES, onde cada cliente possui NOME, RG,
ENDERECO E TELEFONE.
9
Na linguagem de ARQUIVOS, cada OCORRÊNCIA de cliente num arquivo é chamado de
REGISTRO e cada informação dentro do REGISTRO do cliente é chamada de CAMPO.
Num arquivo com 10 clientes, dizemos que há 10 registros. No exemplo acima, dizemos que os
campos do REGISTRO de Clientes são : NOME, RG, ENDEREÇO e TELEFONE.

OBS. : A função sizeof retorna a quantidade de bytes de um


determinado tipo
ou variável

Exemplo :

sizeof(int)  retorna 2 de acordo com o tipo de máquina


sizeof(struct cliente)  retorna a somatória de bytes da struct cliente

Exemplos :

O PROGRAMA ABAIXO CRIA UM ARQUIVO E GRAVA OS DADOS NESTE ARQUIVO

#include <stdio.h>
#include <conio.h>

#define LETRAS 50
struct Tcliente {
char situacao; // situacao do registro : excluido ou nao ?
int codigo; // codigo do sujeito
char nomecli[LETRAS]; // nome do sujeito
char fone [15]; // fone do sujeito
char sexo; // sexo
float limite; // limite de credito
};

// prototipos
void Entrada (FILE *);
char ValidaSexo();
char Validaresp();

// =================================================================
void main() {
FILE *cliente;
char verro = 'N';
char arqcli [] = {"CLIENTE.DAD"};

cliente = fopen(arqcli, "rb+");


if (cliente == NULL) {
printf(" \n Arquivo %s Nao existe : Tecle algo para criar agora ! ", arqcli);
getch();

if ((cliente = fopen(arqcli, "wb+")) == NULL) {


verro = 'S';
printf(" \n Erro grave ! Nao consigo criar o arquivo %s !!!", arqcli);
getch();
}
}

if (verro == 'N') {
Entrada(cliente);
fclose (cliente);
}
10
}

// entrada de dados gravando direto em arquivo


void Entrada (FILE * cliente) {
int retorno;
struct Tcliente Vcli;
char vresp;

do {
clrscr();
printf("\n Digite o Codigo [Zero encerra] : " );
scanf("%d", &Vcli.codigo);
if (Vcli.codigo != 0) {
printf(" \n Digite o nome : ");
fflush(stdin);
gets(Vcli.nomecli);
Vcli.sexo = ValidaSexo();
printf(" \n Digite o Fone : " );
gets(Vcli.fone);
printf(" \n Digite o Limite de Credito do cliente : ");
scanf("%f", &Vcli.limite);
vresp = Validaresp();
if (vresp == 'S') {
retorno = fwrite (&Vcli, sizeof(struct Tcliente) ,1,cliente);
// fwrite retorna a quantidade de itens gravados (NAO BYTES)
if (retorno == 1) {
printf(" \n Gravacao ok ! ");
getch();
}
else {
printf (" \n Problemas : Gravacao nao efetuada !!!" );
getch();
}
}
}
} while (Vcli.codigo != 0);
}
// validar o sexo
char ValidaSexo() {
char vsexo;
do {
printf(" \n Digite o Sexo [M ou F] : " );
vsexo = getche();
} while (vsexo != 'F' && vsexo != 'M');
return vsexo;
}

// validar a respostar
// validar o sexo
char Validaresp() {
char vresp;
do {
printf(" \n Confirma Inclusao [S ou N] ? " );
vresp = getche();
} while (vresp != 'S' && vresp != 'N');
return vresp;
}
11
O PROGRAMA ABAIXO ABRE UM ARQUIVO E IMPRIME OS DADOS NA TELA
#include <stdio.h>
#include <conio.h>

#define LETRAS 50
struct Tcliente {
char situacao; // situacao do registro : excluido ou nao ?
int codigo; // codigo do sujeito
char nomecli[LETRAS]; // nome do sujeito
char fone [15]; // fone do sujeito
char sexo; // sexo
float limite; // limite de credito
};

// prototipos
void Le_Imprime (FILE *);

void main() {
FILE *cliente;
char verro = 'N';
char arqcli [] = {"CLIENTE.DAD"};

if ((cliente = fopen(arqcli, "rb")) == NULL) {


verro = 'S';
printf(" \n Erro Grave : Arquivo Nao existe !");
getch();
}

if (verro == 'N') {

Le_Imprime(cliente);

fclose (cliente);
}

// Le dados de um arquivo e imprime na Tela


void Le_Imprime (FILE * cliente) {
int retorno, cont = 0;
struct Tcliente Vcli;

retorno = fread(&Vcli, sizeof(struct Tcliente), 1, cliente);


// fread retorna a quantidade de itens retornados ...
clrscr();
while ( retorno == 1) {
cont++;
printf("\n\n DADOS DO CLIENTE %d \n", cont);
printf("\n Codigo : %d", Vcli.codigo);
printf("\n Nome ..: %s", Vcli.nomecli);
printf("\n Sexo ..: %c", Vcli.sexo);
printf("\n Fone ..: %s", Vcli.fone);
printf("\n Limite : %.2f", Vcli.limite);
retorno = fread(&Vcli, sizeof(struct Tcliente), 1, cliente);

}
printf(" \n\n %d clientes cadastrados ", cont);
getch();
}