Manipulação de Arquivos Devemos iniciar nossa explanação pelo conceito de arquivo: Arquivo é uma unidade lógica utilizada para armazenar dados em disco ou em qualquer outro dispositivo externo de armazenamento. Pode-se abrir, fechar, ler, escrever ou apagar um arquivo. A linguagem C manipula tanto arquivos quanto dispositivos de I/O, se utilizando do conceito de ponteiro para arquivo. Sendo disponibilizada uma série de funções para trabalhar com este conceito, cujos protótipos estão reunidos em stdio.h. 493
Manipulação de Arquivos A definição do ponteiro para arquivo também está no arquivo stdio.h. Podemos declarar um ponteiro para arquivo da seguinte maneira: FILE *p; Os arquivos podem ser classificados em: - binários; - texto. 494
Manipulação de Arquivos - fopen() Esta é a função de abertura de arquivos. Seu protótipo é: FILE *fopen (char *nome_do_arquivo,char *modo); 495
496
Manipulação de Arquivos Poderíamos então, para abrir um arquivo binário para escrita, escrever:... FILE *fp; fp=fopen ("exemplo.bin","wb"); if (!fp) printf ("Erro na abertura do arquivo."); A condição!fp testa se o arquivo foi aberto com sucesso, porque no caso de um erro a função fopen() retorna um ponteiro nulo (NULL). 497
Manipulação de Arquivos Uma vez aberto um arquivo, vamos poder ler ou escrever nele utilizando as funções que serão apresentadas a seguir. Toda vez que estamos trabalhando com arquivos, há uma espécie de posição atual no arquivo. Esta é a posição de onde será lido ou escrito o próximo dado. Normalmente, num acesso sequencial a um arquivo, não temos que mexer nesta posição. Pois, quando lemos um dado a posição no arquivo é automaticamente atualizada. Num acesso randômico teremos que mexer nesta posição. 498
Manipulação de Arquivos - fclose Quando acabamos de usar um arquivo que abrimos, devemos fechá-lo. Para tanto, usa-se a função fclose(), cujo protótipo é: int fclose (FILE *fp); O ponteiro fp passado à função fclose() determina o arquivo a ser fechado. A função retorna zero no caso de sucesso. 499
Manipulação de Arquivos Fechar um arquivo faz com que qualquer dado que tenha permanecido no "buffer" associado ao fluxo de saída seja gravado. A função exit() fecha todos os arquivos que um programa tiver aberto. 500
Manipulação de Arquivos - putc A função putc é a primeira função de escrita em arquivo que veremos. Seu protótipo é: int putc (int ch, FILE *fp); 501 A referida função escreve um caractere no arquivo apontado por fp. O que putc() retorna? e para que é útil este retorno?
#include <stdio.h> /*Exemplo*/ int main() { FILE *fp; char c; fp = fopen("arquivo.txt","w"); if(!fp) { printf( "Erro na abertura do arquivo"); exit(1); } printf("entre com um caractere para ser gravado no arquivo: "); scanf("%c", &c); putc(c, fp); fclose(fp); return 0; } 502
#include <stdio.h> /*Exemplo*/ int main() { FILE *fp; char c; fp = fopen("arquivo.txt","w"); if(!fp) { printf( "Erro na abertura do arquivo"); exit(1); } printf("entre com um caractere para ser gravado no arquivo: "); scanf("%c", &c); if (c == (char) putc(c, fp)) printf("tudo deu certo!"); else prinff("ocorreu um erro!"); fclose(fp); return 0; } 503
Manipulação de Arquivos Exercício: Com o que vimos até o momento sobre manipulação de arquivos. Construa uma função em C que possua a capacidade de escrever uma string em um arquivo texto. Escreva um programa que se utiliza adequadamente da função que você implementou. 504
505 #include <stdio.h> void putstrinfile (FILE *, char*); int main() { FILE *fp; char string[100]; int i; fp = fopen("arquivo.txt","w"); if(!fp) } { printf( "Erro na abertura do arquivo"); exit(1); } printf("entre com a string a ser gravada no arquivo:"); scanf("%[^\n]", string); putstrinfile (fp, string) ; fclose(fp); return 0;
506 void putstrinfile (FILE *fp, char* string) { int i; for(i=0; string[i]; i++) putc(string[i], fp); }
- getc Manipulação de Arquivos Seu protótipo é: int getc (FILE *fp); A função retorna um caractere lido do arquivo apontado por fp. OBS.: Equivalente à fgetc(). Exercício: Construa um função em C que possua a capacidade de ler e apresentar na saída padrão uma string contida em um arquivo texto. 507
508 - feof Manipulação de Arquivos EOF ("End Of File") indica o fim de um arquivo. Às vezes, é necessário verificar se um arquivo chegou ao fim. Para isto podemos usar a função feof(). Ela retorna não-zero se o arquivo chegou ao EOF, caso contrário retorna zero. Seu protótipo é: int feof (FILE *fp); Outra forma de se verificar se o final do arquivo foi atingido é comparar o caractere lido por getc() com EOF. O programa a seguir abre um arquivo já existente e o lê, caractere por caractere, até que o final do arquivo seja atingido. Os caracteres lidos são apresentados na tela:
509 #include <stdio.h> int main() { FILE *fp; int c; fp = fopen("arquivo.txt","r"); if(!fp) { } printf( "Erro na abertura do arquivo"); exit(1); } while((c = getc(fp) )!= EOF) printf("%c", (char)c); fclose(fp); return 0;
510 #include <stdio.h> int main() { FILE *fp; fp = fopen("arquivo.txt","r"); if(!fp) { printf( "Erro na abertura do arquivo"); exit(1); } while(!feof(fp)) printf("%c", (char)getc(fp)); fclose(fp); return 0; }
/*Resposta de exercício do slide 512*/ void get_string(file *fp) { int c; while ((c = getc(fp))!= EOF) printf("%c", (char)c); } 511
Manipulação de Arquivos - Arquivos pré-definidos Quando se começa a execução de um programa, o sistema automaticamente abre alguns arquivos pré-definidos: stdin: dispositivo de entrada padrão (geralmente o teclado); stdout: dispositivo de saída padrão (geralmente o vídeo); stderr: dispositivo de saída de erro padrão (geralmente o vídeo); stdaux: dispositivo de saída auxiliar (em muitos sistemas, associado à porta serial); stdprn : dispositivo de impressão padrão (em muitos sistemas, associado à porta paralela). 512
513 Manipulação de Arquivos Cada uma destas constantes pode ser utilizada como um ponteiro para FILE, para acessar os periféricos associados a eles. Desta maneira, pode-se, por exemplo, usar: char ch = (char)getc(stdin); para efetuar a leitura de um caractere a partir do teclado, ou: putc(ch, stdout); para imprimir o mesmo no monitor.
514 Manipulação de Arquivos Com base no que vimos, podemos agora entender melhor o processo de leitura de valores fornecidos través da entrada padrão. Sempre que nos utilizamos de uma função para leitura de valores através do teclado, estamos solicitando que seja efetuada uma leitura na stream (buffer) que representa o arquivo apontado por stdin. Quando não é encontrado algo na stream ocorre uma espera pelo fornecimento de valores através do teclado, ou melhor, ocorre uma espera por pressionamento(s) de tecla(s) no teclado.
Exercício: Manipulação de Arquivos Com base no que foi discutido, podemos construir um programa que leia uma string fornecida pelo usuário, através da entrada padrão, e a retorne na saída padrão. O comprimento máximo da string é de vinte caracteres válidos. A identificação do final da string é caracterizada pelo pressionamento da tecla enter ou ao se atingir o limite de caracteres válidos. 515
- fgets Manipulação de Arquivos Para se ler uma string num arquivo podemos usar fgets() cujo protótipo é: char *fgets (char *str, int tamanho,file *fp); A função lê a string até que um caractere de nova linha seja lido ou tamanho-1 caracteres tenham sido lidos. Se o caractere de nova linha ('\n') for lido, ele fará parte da string, o que não acontecia com gets. A string resultante sempre terminará com '\0' (por isto somente tamanho-1 caracteres, no máximo, serão lidos). 517
Manipulação de Arquivos A função fgets é semelhante à função gets(), porém, além dela poder fazer a leitura a partir de um arquivo de dados e incluir o caracter de nova linha na string, ela ainda especifica o tamanho máximo da string de entrada. Como vimos, a função gets() não tinha este controle, o que poderia acarretar erros de "estouro de buffer". Portanto, levando em conta que o ponteiro fp pode ser substituído por stdin, como vimos anteriormente, uma alternativa ao uso de gets é usar a seguinte construção: int tamanho=11; char str[11]; fgets (str, tamanho, stdin); 518
Exercício: Manipulação de Arquivos Construa um programa em C que receba o nome de um arquivo, fornecido pelo usuário, através da entrada padrão, e efetue a abertura do mesmo para uma leitura. O nome do arquivo fornecido deve possuir no máximo 20 caracteres. 519
Manipulação de Arquivos - fputs A função fputs() escreve uma string num arquivo. Seu protótipo é: char *fputs (char *str, FILE *fp); 521
- fflush Seu protótipo é: Manipulação de Arquivos int fflush (FILE *fp); A função fflush() esvazia o buffer do arquivo referenciado pelo ponteiro passado como argumento, se o arquivo passado for um arquivo de saída o conteúdo do buffer é gravado no mesmo. Se a função for chamada sem parâmetros, os buffers de todos os arquivos abertos para saída serão descarregados. A função devolve 0 para indicar sucesso, caso contrário devolve EOF. 522
Manipulação de Arquivos - ferror A função ferror() determina se uma operação com arquivo produziu um erro. Seu protótipo é: int ferror (FILE *fp); A função ferror() retorna um inteiro não nulo se ocorreu um erro durante a última operação no arquivo; caso contrário retorna zero. 523
524 /* Exemplo da utilização da função ferror() */ #include <stdio.h> int main() { FILE *pf; char string[100]; if(!(pf = fopen("arquivo.txt","wb"))) exit(1); do { printf("\ndigite uma nova string. Para terminar, digite <enter>: "); fgets(string,100,stdin); fputs(string, pf); if(ferror(pf)) exit(1); } while (strlen(string) > 1); fclose(pf); return 0; }
525 Exercício: Manipulação de Arquivos Construa um programa em C que receba da linha de comando, com a qual o programa foi executado, o nome de um arquivo texto existente, o qual deve ser analisado, afim de se determinar quantas linhas o mesmo tem, após a referida analise, o programa deve incluir uma nova linha no final do arquivo contendo o número de linhas que o mesmo possuía. Caso ocorra algum erro durante o processamento, o mesmo deve ser identificado através da exibição de uma mensagem na saída padrão. Observação o número máximo de caracteres que cada linha contém é 80.
528 Podemos escrever e ler blocos de dados em um determinado arquivo. Para tanto, a linguagem C, disponibiliza as funções fread() e fwrite(). - fread Manipulação de Arquivos O protótipo de fread() é: unsigned int fread (void *buffer, int numero_de_bytes, int count, FILE *fp); A função retorna o número de unidades efetivamente lidas. Este número pode ser menor que count quando o fim do arquivo for encontrado ou ocorrer algum erro.
- fwrite Manipulação de Arquivos A função fwrite() funciona como fread(), porém escrevendo no arquivo. Seu protótipo é: unsigned int fwrite(void *buffer, int numero_de_bytes, int count, FILE *fp); A função retorna o número de itens escritos. Este valor será igual a count, a menos que ocorra algum erro. O exemplo a seguir ilustra o uso de fwrite() e fread() para gravar e posteriormente ler uma variável float em um arquivo binário. 529
530 #include <stdio.h> int main() { FILE *pf; float pi = 3.1415, pilido; if(!(pf = fopen("arquivo.bin", "wb"))) exit(1); if(fwrite(&pi, sizeof(float), 1,pf)!= 1) { printf("erro na escrita do arquivo!"); exit(2); } fclose(pf); if(!(pf = fopen("arquivo.bin", "rb"))) exit(1); if(fread(&pilido, sizeof(float), 1,pf)!= 1) { printf("erro na leitura do arquivo!"); exit(3); } printf("\no valor de PI, lido do arquivo e': %.4f", pilido); fclose(pf); return(0); }
Exercício: Manipulação de Arquivos Construa funções na linguagem C que manipulem um determinado arquivo que contém registros, efetuando operações de escrita e leitura respectivamente. Um registro contém código, nome e salário de um funcionário especifico. Uma função deve escrever e a outra ler um determinado registro no arquivo especificado. 531
Manipulação de Arquivos - fseek Para se fazer procuras e acessos randômicos em arquivos usa-se a função fseek(). Esta move a posição corrente de leitura ou escrita no arquivo de um valor especificado, a partir de um ponto especificado. Seu protótipo é: int fseek (FILE *fp, long int numbytes, int origem); 533
Exercício: Manipulação de Arquivos Com base no exercício do slide 460, construa mais uma função, capaz de inserir um determinado registro em uma determinada posição em um arquivo. Observação: A função deve receber o nome do arquivo a ser manipulado e o número de registros contido no mesmo entre os seus parâmetros. 534
Manipulação de Arquivos 536 - rewind A função rewind() de protótipo void rewind (FILE *fp); retorna a posição corrente do arquivo para o início. - remove Protótipo: int remove (char *nome_do_arquivo); Apaga um arquivo especificado, retornando zero caso seja bem sucedida; caso contrário, retorna um não nulo.
Manipulação de Arquivos Exercício: Com o que vimos até o momento sobre manipulação de arquivos. Construa um programa na linguagem C que, utilizando-se da função definida no exercício do slide 504, possua a capacidade de escrever strings em um arquivo texto denominado arquivo.txt. O programa receberá uma sequência de strings, através da entrada padrão, as escrevendo no arquivo, uma string em cada linha. O programa ao receber uma string vazia finaliza sua execução. 537
Alocação Dinâmica de Memória - Exercício Exemplo de entrada: Marcelo Linder Um otimo professor Estudem Exemplo de Saída na tela: Conteúdo do arquivo denominado arquivo.txt após execução do programa: Marcelo Linder Um otimo professor Estudem 538
539 void putstrinfile (FILE *fp, char* string) { int i; for(i=0; string[i]; i++) putc(string[i], fp); }