Linguagem C arquivos IF61A/IF71A - Computação 1 Prof. Leonelo Almeida Universidade Tecnológica Federal do Paraná
Até agora... Introdução à linguagem C... Vetores Matrizes Funções Recursão Registros Ponteiros
Aula de hoje E se eu quiser armazenar os dados informados pelo usuário em uma execução do meu programa e recuperá-los quando o programa for executado novamente?
Aula de hoje E se eu quiser armazenar os dados informados pelo usuário em uma execução do meu programa e recuperá-los quando o programa for executado novamente? Até agora todos os programas que fizemos utilizam somente a memória RAM, que é volátil e disponível somente durante a execução do programa.
Aula de hoje Manipulação de arquivos em C
Memórias RAM Volátil Requer alimentação de energia contínua para manter dados ENTRADA SAÍDA
Memórias Persistente Não requer energia para manter dados RAM Volátil Requer alimentação de energia contínua para manter dados ENTRADA HARD DISK Pen-drives CDs, DVDs SAÍDA
Memórias e Arquivos Programas sempre são executados com a memória RAM (memória primária) Se a energia acabar, os programas precisam ser reinicializados Arquivos são gravados em disco rígido (memória secundária)
Arquivos São geralmente identificados por nomes e extensões Extensões geralmente informam o tipo de conteúdo armazenado no arquivo (mas não garante nem converte entre tipos de conteúdo) Exemplos: desespero.c (para códigos fonte em C) index.html (para documentos Web)
Tipos de arquivo Do ponto de vista de programação, existem dois tipos somente: Arquivos texto: caracteres que pode ser mostrados na tela e editados por um editor de texto simples Exemplo: código fonte em C, páginas em HTML Arquivos binários: sequência de bits que são definidas por um programa. Não são legíveis diretamente. Exemplo: arquivos executáveis, arquivos compactados
Tipos de arquivo Arquivos texto: Cada caractere ou dígito é convertido de acordo com a tabela de caracteres (e.g. ASCII) e ocupa 8 bits cada Arquivos binários: Os dados são gravados diretamente Exemplo int n = 12345678; Arquivo texto = 64 bits (8 bits por dígito) Arquivo binário = 32 bits (4 bits por dígito)
Estrutura de diretórios (ou pastas) São estruturas em árvore que podem conter arquivos e outros diretórios Diretório raiz / C: *Unix Windows home bin Subdiretórios (ou pastas) aluno 1 aluno 2 codeblocks arq.c prova.txt outro.c Arquivos
Caminhos (ou paths) Um arquivo pode ser referenciado de duas maneiras Caminhos absolutos: descreve o caminho completo a partir do diretório raiz Exemplo: /bin/codeblocks /home/aluno1/arq.c Caminhos relativos: descreve o caminho a partir do diretório corrente Exemplo: arq.c aluno2/prova.txt Diretório corrente: /home/aluno1 Diretório corrente: /home
Manipulação de arquivos em C Há um tipo de ponteiro especial para arquivos FILE *nome_variavel; Exemplo: FILE *v_arq; Tal como um ponteiro normal é necessário associá-lo a algo. No caso, um arquivo.
Manipulação de arquivos em C Para associar arquivos a um ponteiro do tipo FILE usamos a função: fopen( caminho/arquivo, modo acesso ); Absoluto ou relativo Exemplo: FILE *v_arq; v_arq = fopen( codigo.c, r ); Dessa maneira, o ponteiro v_arq aponta para o arquivo codigo.c
Modos de acesso arquivos texto Modo Significado Indicador r w a Abre um arquivo texto para leitura (arquivo deve existir antes). Cria um arquivo texto para escrita. Se o arquivo já existe, o conteúdo anterior será apagado! Abre um arquivo texto existente para escrita no final. r+ Abre um arquivo texto para leitura e escrita. Se o arquivo já existe, o conteúdo anterior não é apagado. w+ Cria um arquivo texto para leitura e escrita. Se o arquivo já existe, o conteúdo anterior será apagado! a+ Abre (ou cria) um arquivo texto para leitura e escrita (no final do arquivo). Início Início Fim Início Início Fim
Modos de acesso arquivos binários Modo Significado Indicador rb wb ab r+b w+b a+b Abre um arquivo binário para leitura (arquivo deve existir antes). Cria um arquivo binário para escrita. Se o arquivo já existe, o conteúdo anterior será apagado! Abre um arquivo binário existente para escrita no final. Abre um arquivo binário para leitura e escrita Se o arquivo já existe, o conteúdo anterior não é apagado. Cria um arquivo binário para leitura e escrita. Se o arquivo já existe, o conteúdo anterior será apagado! Abre (ou cria) um arquivo binário para leitura e escrita (no final do arquivo). Início Início Fim Início Início Fim
Exemplo FILE *arq; arq = fopen( teste.c, w ); Permite verificar se a abertura foi realizada corretamente. if (arq == NULL) { printf( Não foi possível abrir o arquivo\n );
Leitura de dados em arquivos Há um indicador de posição no arquivo aberto O indicador aponta para o início do arquivo A cada leitura de dados o indicador de posição é incrementado para o próximo dado no arquivo Quando chega ao fim do arquivo, o indicador recebe o valor EOF (de end of file).
Agora veremos comandos para leitura e escrita em arquivos binários e em arquivos texto
Leitura e escrita em arquivos texto
Leitura de dados de arquivos texto Usamos a função fscanf() Semelhante à função scanf() Mas lê os dados de um arquivo fscanf(file *arquivo, formato, variáveis); Exemplo: char aux; FILE *arq = fopen( teste.txt, r ); fscanf(arq, %c, &aux); printf( %c, aux);
Exemplo Lê todos os dados de um arquivo. char aux; FILE *arq = fopen( teste.txt, r ); while (fscanf(arq, %c, &aux)!= EOF){ printf( %c, aux); fclose(arq); Fecha um arquivo e garante que dados escritos foram realmente gravados.
Exemplo #include <stdio.h> int main() { FILE *arq; char aux, nomearq[100]; printf( Nome do arquivo:"); scanf("%s", nomearq); arq = fopen(nomearq, "r"); if (arq == NULL) printf("erro ao abrir o arquivo: teste.txt"); else{ printf("------ Dados do arquivo:\n\n"); while(fscanf(arq,"%c",&aux)!= EOF){ printf("%c",aux); fclose(arq);
Escrita de dados em arquivos texto Para habilitar a escrita usamos a função fopen() com o modo de acesso w A escrita é feita pela função fprintf() Semelhante à função printf() Mas em ver de imprimir na saída padrão, escreve os dados no arquivo. fprintf(file *arquivo, texto, variáveis);
Exemplo FILE *arqr = fopen ("teste.txt", "r"); FILE *arqw = fopen ("saida.txt", "w"); char aux; while (fscanf(arqr, "%c", &aux)!= EOF) { fprintf(arqw,"%c", aux); fclose(arqr); fclose(arqw); O que haverá no arquivo saida.txt após a execução do programa?
Exemplo E se quisermos ler todo o texto de um arquivo em um vetor, alterá-lo e, depois, gravá-lo novamente no arquivo?
int main() { FILE *arq; char texto[1001], aux, nomearqin[100]; int i; printf("entre com nome do arquivo de entrada:"); scanf("%s", nomearqin); arq = fopen(nomearqin, "r"); if (arq == NULL){ printf("erro: %s\n",nomearqin); return 0; for(i=0; i<1000 && fscanf(arq,"%c",&aux)!= EOF; i++){ texto[i] = aux; texto[i] = '\0'; fclose(arq);... Abre o arquivo como leitura e copia os dados para um vetor //continua
... arq = fopen(nomearqin, "w"); if (arq == NULL){ printf("erro: %s\n",nomearqin); return 0; for(i=0; texto[i]!= '\0'; i++){ if(texto[i] == 'a') fprintf(arq,"%c", 'A'); else fprintf(arq,"%c", texto[i]); fclose(arq); Como estará o arquivo após a execução deste programa?
Leitura e escrita em arquivos texto Outras funções: Escreve somente um caractere no arquivo: fputc(caractere, ponteiro_arquivo); Exemplo: char carac= A ; fputc(carac, arq); Lê somente um caractere do arquivo : int fgetc(ponteiro_arquivo); Exemplo: char carac; carac = fgetc(arq);
#include <stdio.h> #include <ctype.h> int main() { FILE *f1, *f2; f1 = fopen("minusculo.txt","r"); f2 = fopen("maiusculo.txt","w"); if (f1==null f2==null) { printf("erro na abertura\n"); system("pause"); exit(1); char aux = fgetc(f1); while (aux!= EOF) { fputc(toupper(aux),f2); aux = fgetc(f1); fclose(f1); fclose(f2); return 0; Exemplo O que faz esse programa?
#include <stdio.h> #include <ctype.h> int main() { FILE *f1, *f2; f1 = fopen("minusculo.txt","r"); f2 = fopen("maiusculo.txt","w"); if (f1==null f2==null) { printf("erro na abertura\n"); system("pause"); exit(1); char aux = fgetc(f1); while (aux!= EOF) { fputc(toupper(aux),f2); aux = fgetc(f1); fclose(f1); fclose(f2); return 0; Exemplo Abre o arquivo minusculo.txt e grava todo o seu conteúdo em maiusculo.txt. Mas converte todas as letras para maiúsculas.
#include <stdio.h> #include <ctype.h> int main() { FILE *f1, *f2; f1 = fopen("minusculo.txt","r"); f2 = fopen("maiusculo.txt","w"); if (f1==null f2==null) { printf("erro na abertura\n"); system("pause"); exit(1); char aux = fgetc(f1); while (aux!= EOF) { fputc(toupper(aux),f2); aux = fgetc(f1); fclose(f1); fclose(f2); return 0; Exemplo A função exit() encerra o programa e retorna um int para o sistema operacional. Enquanto que o return encerra somente a função. A função toupper converte um caractere em seu equivalente maiúsculo.
Leitura e escrita em arquivos texto Escreve uma cadeia de caracteres no arquivo: fputs(cadeia_caract, ponteiro_arquivo); Exemplo: char cad[5] = ABCD ; fputs(cad, arq); Lê uma cadeia de caracteres do arquivo: int fgets(cadeia_caract, tamanho, ponteiro_arquivo); Exemplo: char cad[5]; fgets(cad, 5, arq); Sempre considerar o \0 no final da string. Para a leitura se encontrar uma quebra de linha (\n).
Leitura e escrita em arquivos binários
Escrita em arquivos binários Para escrever blocos de bytes usamos: int fwrite(void *buffer, int bytes, int unidades, FILE *arquivo) Onde: Buffer: ponteiro para os dados que serão gravados Bytes: tamanho de cada unidade a ser gravada Unidades: número de unidades que serão gravadas Arquivo: ponteiro para o arquivo Retorno: total de unidade de dados escritas
Exemplo #include <stdio.h> int main() { FILE *arq = fopen("teste.txt","wb"); if (arq == NULL) { printf("erro"); exit(1); int total_gravado, vet[5] = {1,2,3,4,5; total_gravado = fwrite(vet, sizeof(int), 5, arq); if(total_gravado!= 5) { printf("erro"); exit(1); fclose(arq); return 0;
Exemplo #include <stdio.h> int main() { FILE *arq = fopen("teste.txt","wb"); if (arq == NULL) { printf("erro"); exit(1); int total_gravado, vet[5] = {1,2,3,4,5; total_gravado = fwrite(vet, sizeof(int), 5, arq); if(total_gravado!= 5) { printf("erro"); exit(1); fclose(arq); return 0; A função sizeof(tipo_de_dados) retorna o tamanho em bytes do tipo de dados passado como parâmetro.
Leitura em arquivos binários Para ler blocos de bytes usamos: int fread(void *buffer, int bytes, int unidades, FILE *arquivo) Onde: Buffer: Ponteiro para os dados que serão lidos Bytes: tamanho de cada unidade a ser lida Unidades: número de unidades que serão lidas Arquivo: ponteiro de arquivo Retorno: total de unidades de dados lidas
Exemplo #include <stdio.h> int main() { FILE *arq = fopen("teste.txt", rb"); if (arq == NULL) { printf("erro"); exit(1); int total_lido, vet[5]; total_lido = fread(vet, sizeof(int), 5, arq); if(total_lido!= 5) { printf("erro"); exit(1); fclose(arq); return 0; Também é possível ler mais de uma variável de tipos iguais
Exemplo... //Abertura do arquivo... int vet[5]; char nome[51]; float val; Por que só o float tem & no fread()? fread(vet, sizeof(int), 5, arq); fread(nome, sizeof(char), 20, arq); fread(&val, sizeof(float), 1, arq); printf( vet: { %d, %d, %d, %d, %d \n, vet[0], vet[1], vet[2], vet[3], vet[4]); printf( Nome: %s \n, nome); printf( Valor: %.2f \n, val); fclose(arq); return 0;
Busca, Acesso e remoção de arquivos
Buscas e acessos não sequenciais em arquivos É possível fazer acessos não sequenciais em arquivos A função fseek() move o indicador de posição para uma posição especificada int fseek(file *arq, long numbytes, int origem); Onde: Numbytes: número de bytes (pode ser negativo) a partir da origem Origem: posição do arquivo a partir da qual o indicador de posição será movido em numbytes SEEK_SET início do arquivo SEEK_CUR posição corrente SEEK_END final do arquivo Retorno: 0 quando foi executado com sucesso.
Exemplo (gerando um arquivo...) struct cadastro { char nome[20], apelido[20]; int idade; int main(){ FILE *arq = fopen( teste.txt, wb ); if (arq == NULL) { printf( Erro ); exit(1); struct cadastro cad[4] = { João, Jô, 18, Joana, Jô, 21, Jonas, Jô, 44, José, Zé, 35; fwrite(cad, sizeof(struct cadastro), 4, arq); fclose(arq); return 0;
Exemplo (buscando dados...) struct cadastro { char nome[20], apelido[20]; int idade; int main(){ FILE *arq = fopen( teste.txt, rb ); if (arq == NULL) { printf( Erro ); exit(1); struct cadastro cad; fseek(arq, 2*sizeof(struct cadastro), SEEK_SET); fread(&cad, sizeof(struct cadastro), 1, arq); printf( nome: %s, apelido: %s, idade: %d, cad.nome, cad.apelido, cad.idade); fclose(arq); return 0; O que será impresso?
Exemplo (buscando dados...) struct cadastro { char nome[20], apelido[20]; int idade; int main(){ FILE *arq = fopen( teste.txt, rb ); if (arq == NULL) { printf( Erro ); exit(1); struct cadastro cad; Pula os dois primeiros cadastros a partir do início do arquivo. fseek(arq, 2*sizeof(struct cadastro), SEEK_SET); fread(&cad, sizeof(struct cadastro), 1, arq); printf( nome: %s, apelido: %s, idade: %d, cad.nome, cad.apelido, cad.idade); fclose(arq); return 0; Imprime o terceiro registro: nome: Jonas, apelido: jô, idade: 44
A função rewind() A cada leitura o indicador de posição avança automaticamente até chegar em EOF Para o indicador voltar ao início do arquivo use a função rewind(ponteiro_arquivo);
Exemplo... while(fscanf(arq,"%c",&aux)!= EOF){ printf("%c",aux); rewind(arq); while(fscanf(arq,"%c",&aux)!= EOF){ printf("%c",aux);...
Remoção de arquivos É possível apagar arquivos em um programa C remove(caminho_arquivo); Exemplo: remove( teste.txt ); Muito cuidado ao usar esse comando!
Dicas importantes Line Feed (LF) Quebra de linha Caractere de número 10 na tabela ASCII Carriage Return (CR) Retorno ao começo da linha Caractere de número 13 na tabela ASCII
Atividades Gravar as tabelas de dados do projeto em arquivo(s). Recuperar os dados do(s) arquivo(s), editá-lo e gravar os dados nele(s) novamente.