8. - Ficheiros

8.1. Introdução

Até ao momento, todos os dados têm sido inseridos nos programas através do teclado, sendo guardados em variáveis, as quais residem em memória central (também chamada de R.A.M, memória primária ou volátil) . Esta apresenta no entanto os inconvenientes de ser volátil e cara, pelo que se torna desinteressante para o armazenamento durante periodos que excedam o de execução de um programa. Para armazenamentos mais demorados é utilizado outro meio, a que se chama memória secundária ( i.e. o disco rígido, ou a disquete), em que a informação é armazenada sob a forma de ficheiros. A utilização destas estruturas (ficheiros) na linguagem C será o assunto deste capítulo. As funções que irão ser estruturadas fazem parte da biblioteca padrão, e portanto obrigam à inclusão nos programas da seguinte linha, já conhecida:

#include <stdio.h>

Qualquer processo (programa) tem 3 ficheiros automáticamente abertos : o da entrada padrão ( standar input), o da saída padrão ( standard output), e o da saída de erro ( standard error output). A menos que redireccionados, estão normalmente associados ao terminal, isto é , ao teclado, ao monitor e monitor respectivamente. A cada um destes ficheiros corresponde uma constante, definida em stdio.h que o identifica:

- stdin standard input (teclado)
- stout standard output (monitor)
- stderr standard error (monitor)

O ficheiro de saída de erro é geralmente usado para escrever mensagens de erro que não dizem respeito às saidas normais. Por exemplo, se ocorresse um erro grave seria aborrecido se a mensagem de erro fosse redireccionada para o ficheiro de saída sem que o utilizador se apercebesse disso. A solução seria escrever a mensagem para o standard error.

A linguagem C permite dois tipos de ficheiros : binário, ou texto. Estes são um conjunto de linhas, com zero ou mais caracteres cada, sendo cada uma terminada pelo caractere newline (\n). Estas linhas estão sujeitas a algum processamento feito pelo sistema operativo. Por exemplo o DOS na escrita, substitui o \n por carriage return e mudança de linha (line feed). A substituição inversa é feita na leitura.

Um ficheiro binário, é composto por uma sequência de bytes(caracteres) que não são alterados pelo sistema.

8.2. Abertura e Fecho de Ficheiros

O ficheiro stdio.h contém definições e declarações necessárias às funções standards de manipulação de ficheiros. Esse ficheiro contém um typedef que define um tipo de dado chamado file. Nos programas em linguagem C um ficheiro é especificado em termos de um apontador para um FILE que é obtido pela chamada à função fopen. O utilizador não necessita conhecer os membros de uma estrutura FILE. A sintaxe da função de abertura de ficheiros num programa em C é:

FILE *fopen(char nome_do_ficheiro[], char modo[]);

A função fopen() devolve um apontador para um FILE, que passa a ser utilizado em todos os acessos ao ficheiro. O primeiro argumento é o nome do ficheiro a ser aberto. O segundo argumento é o modo de abertura. Algumas das possibilidades para o argumento modo são:

- R :Abertura para leitura.Dá erro se o ficheiro não existe.
- W :Abertura para escrita.Se o ficheiro existir o conteúdo é apagado. Se não existir, o ficheiro é criado.
- A :Abertura para adição no fim do ficheiro.Se este existir então os novos dados serão escritos no fim do ficheiro.Se o ficheiro não existir então será criado.
- R+ :Abertura do ficheiro para leitura e escrita.
- b,t :Conforme se trate de um ficheiro do tipo binário ou do tipo texto, adiciona-se b ou t a qualquer uma das opções anteriores (e.g.:wb).

A função fopen() retorna NULL se ocorrer um erro na abertura. Após ser realizado o processo sobre um ficheiro aberto à que fechá-lo. A operação de fecho de um ficheiro é feita pela função :

fclose (FILE *fp);

Esta função desaloca a estrutura FILE respectiva e fecha o ficheiro apontado por fp. Em caso de erro (i.e. fechar um ficheiro que ainda não foi aberto) retorna EOF, caso contrário retorna zero.

Exemplo : Exemplo de chamadas às funções fopen e fclose.

#include <stdio.h>
FILE *fp,*fopen();
...
fp=fopen(dados,r);
...
fclose (fp);

Neste exemplo o valor (apontador para um FILE ) retornado por fopen(), é guardado na variável fp. A partir daqui todas as referências ao ficheiro são feitas usando fp.

8.3. Leitura e Escrita de Ficheiros

Funções Gerais

A função de leitura geral da bibloteca padrão é :

fread(void *buffer, unsigned size, unsigned num, file *fp);

A função fread lê num objectos de tamanho size de um ficheiro especificado pelo apontador fp para a posição de memória indicada por buffer. Retorna o n.º dos objectos completamente lidos, ou retorna 0 se fim de ficheiro. A declaração void * significa apontador para qualquer tipo de variável, ou seja, um qualquer endereço.
A função de escrita geral da standard library é :

fwrite (void *buffer, unsigned size, unsigned num, FILE *fp);

a qual escreve num objectos de tamanho size contidos em buffer, para um ficheiro especificado por fp. Retorna o número de objectos completamente escritos, o qual será igual a num a menos que tenha ocorrido um erro. Notar que, programas escritos com fread e fwrite são portáteirs, mas os ficheiros que foram escritos através destas rotinas poderão não ser, visto as representações dos tipos de dados serem dependentes da máquina.

Orientada à palavra

A linguagem C fornece funções para leitura e escrita de palavras de computador. Assim, palavras individuais (com o tipo de dado int) podem ser lidas e escritas usando as rotinas:

> - getw(FILE *fp);
> - putw(int word,FILE *fp);

O seguinte extracto de um programa

> int x;
> FILE *fp;
> ...
> putw(x,fp);

irá escrever a palavra x no ficheiro especificado por fp. A função retorna a palavra escrita ou EOF caso ocorra um erro. A linha

x=getw(fp);

irá retornar a próxima palavra do ficheiro referido por fp.

Orientada ao Caractere

As rotinas mais primitivas de input e output são getc e putc.Estas rotinas lêm ou escrevem um caracter de cada vez, de e para um ficheiro que é especificado pelo apontador FILE obtido da chamada de fopen(). A chamada

c=getc(fp);

retorna o próximo caracter de um ficheiro especificado por fp ou EOF se foi encontrado o fim do ficheiro (ou, se ocorreu um erro). A chamada

putc(c,fp);

escreve o caracter c no ficheiro especificado por fp. retorna também o caracter c. A ideia que getchar e putchar são funções pode agora ser exposto como uma fraude. Elas são definidas como macros no ficheiro stdio.h da seguinte forma:

> #define getchar() getc(stdin)
> #define putchar() putc(c,stout)

De facto, getc e putc são igualmente macros definidas no stdio.h. A entrada e a saída parecem funcionar caracter a caracter para conveniência do utilizador, mas na realidade eles já são bufferizados.

Com formatação

Existem rotinas para entrada/saída formatada de dados, definidas na biblioteca padrão. Para saída tem-se,

fprintf (FILE *fp, char controle[], arg1, arg2,...)

que é da família da printf, excepto que a saída é escrita para um ficheiro especificado por fp. A função fprintf pode ser usada para escrever num canal diferente do standard output. Caso se especificasse o ficheiro dado pela constante stdout, então fprintf seria o mesmo que printf. Como exemplos ,

> FILE *alunos;
> ...
> alunos=fopen(...);
> ...
> fprintf(alunos,%d, %s\n,numero,nome);
> ...
> fprintf(stderr,Este é o %d-ésimo erro\n,nerro);

As especificações do formato para fprintf são as mesmas das do printf. Ter em atenção, que o printf não trunca o argumento convertido para o ajustar à largura do campo.
Para a leitura formatada a partir de um ficheiro existe a função fscanf, que possui a seguinte sintaxe:

fscanf(fp,controle,arg1,arg2,...)

Funciona de forma idêntica ao scanf, excepto que, lê o input de um ficheiro especificado por fp. A string de controle da função fscanf, é igual à da scanf já estudada. Caso se especificasse o ficheiro dado pela constante stdin, então fscanf seria o mesmo que scanf.

Orientada à Linha

A orientação de linha na entrada e saída pode ser obtida usando as funções fgets, e fputs. A função fgets tem a seguinte sintaxe:

fgets(char linha[],int n, FILE *fp);

Esta função lê a próxima linha de input, incluindo o caracter newline (\n) se existir, de um ficheiro especificado por fp para o array linha. São lidos todos os caracteres até ao caractere newline, a não ser que encontre o fim de ficheiro antes, ou atinja o limite n, e então o array linha é terminado automaticamente com o caracter nulo. Se atingir o fim de ficheiro, ou houver erro, a função retorna NULL.

A função de escrita orientada à linha é a fputs, cuja sintaxe se segue:

fputs(char linha[], FILE *fp);

A função escreve a string linha num ficheiro apontado por fp.

8.4 Acesso Aleatório

Um ficheiro de input e output é normalmente sequencial. O acesso aleatório do ficheiro pode ser obtido usando

fseek(FILE *fp, long deslocamento, int origem);

Uma chamada a fseek força o próximo input ou output do ficheiro fp a tomar lugar numa posição deslocada deslocamento bytes relativamente à origem. Os valores possíveis para origem são:

SEEK_SET => Início do ficheiro
SEEK_CUR => posição corrente no ficheiro
SEEK_END => fim do ficheiro

A função que retorna o deslocamento (Offset) desde o inicio do ficheiro fp é:

long ftell(FILE *fp);

Para voltar ao início do ficheiro apontado por fp existe a função:

rewind(fp);

Esta função é equivalente a : fseek(fp,0L,0);

8.5 Outras Funções de Entrada / Saída

Para completar esta apresentação sobre ficheiros, abordam-se em seguida as funções de controlo de erros e fim de ficheiro.

ferror(fp);

Retorna um número não nulo se ocorreu um erro durante a leitura ou escrita do ficheiro especificado por fp. A função de controle de fim de ficheiro é:

feof(fp);

que retorna um número não nulo se foi atingido o fim de ficheiro senão retorna zero.

Back | Up | Forward

To front page | Pages by Nuno Nunes. |