Baixe o app para aproveitar ainda mais
Prévia do material em texto
A23: Arquivos binários (2), acesso aleatório Algoritmos e Programação Julio Toss jtoss@inf.ufrgs.br INF01202 – Algoritmos e Programação, 2018/01, Turmas G, H, K e L *baseado no material da prof. Mariana e do prof. Marcelo Walter Atenção: O material aqui contido não substitui a leitura do livro texto e é incompleto sem a apresentação do professor em aula. 2 Aula passada Arquivos em C - I/O usa conceito de stream de dados - Ponteiro do tipo * FILE - independente de dispositivos - Operações são “bufferizadas” - binário vs. texto Armazenamento de arquivos binários*: *Assumimos que um arquivo binário contém um conjunto de informações de um mesmo tipo, simples ou estruturado Manipulação de arquivos: 3 Aula passada: utilizando arquivos em C A utilização de arquivos em C (binários ou arquivo texto) envolve os seguintes passos: 1 Declaração do arquivo através de um ponteiro (do tipo específico FILE *) FILE *point_arq; 2 Abertura do arquivo, onde o ponteiro declarado é associado fisicamente ao arquivo externo através de um comando específico (fopen) point_arq = fopen(“nome_do_arquivo”, “modo_de_abertura”) 3 Operações com arquivos, através de funções de manipulação de arquivos (leitura, escrita, dentre outras). Todas estas funções são aplicadas ao ponteiro associado ao arquivo. 4 Fechamento do arquivo, através de um comando específico (fclose) fclose(point_arq); 4 Aula passada: utilizando arquivos em C A utilização de arquivos em C (binários ou arquivo texto) envolve os seguintes passos: 1 Declaração do arquivo através de um ponteiro (do tipo específico FILE *) FILE *point_arq; 2 Abertura do arquivo, onde o ponteiro declarado é associado fisicamente ao arquivo externo através de um comando específico (fopen) point_arq = fopen(“nome_do_arquivo”, “modo_de_abertura”) 3 Operações com arquivos, através de funções de manipulação de arquivos (leitura, escrita, dentre outras). Todas estas funções são aplicadas ao ponteiro associado ao arquivo. 4 Fechamento do arquivo, através de um comando específico (fclose) fclose(point_arq); 5 Aula passada: manipulação de arquivos 6 Para pensar em casa... Escreva um programa que lê os dados de estudantes do ensino médio que prestaram ENEM. O seu programa deve armazenar numa struct os dados: nome do aluno (max 60 caracteres), a idade do aluno e a média final que o aluno obteve (inteiro entre 0 e 100, não precisa fazer validação). Leia os dados e armazene num arquivo binário cujo nome será lido do usuário. O programa deve parar de ler dados quando o usuário digitar a string “Sair” para o nome do aluno. Após a leitura e armazenamento dos dados no arquivo, o programa deve solicitar ao usuário uma média qualquer e o programa deve listar o nome e média de todos os alunos que tiveram média maior ou igual à média informada. Esta informação deve ser obtida a partir da leitura do arquivo salvo. Abaixo exemplo de execução: 7 #include <stdio.h> #include <string.h> #include <stdlib.h> #define STR_MAXLEN 60 typedef struct str_aluno { char nome[STR_MAXLEN+1]; int idade; int media; }aluno_t; int main( ) { aluno_t buffer; FILE *arq; char nome[16]; int media; printf("Nome do arquivo: "); scanf("%s",nome); if(!(arq = fopen(nome,"wb"))) printf("Erro criacao"); else{ //continua... 8 do{ //coleta dados do usuário e grava no arquivo fflush(stdin); printf("\nNome: "); fgets(buffer.nome, STR_MAXLEN, stdin); buffer.nome[ strlen(buffer.nome)-1 ] = '\0'; //remove '\n' if ( strcmp(buffer.nome," Sair") != 0 ) { printf("Idade: "); scanf("%d",&buffer.idade); printf("Media: "); scanf("%d",&buffer.media); if (fwrite(&buffer,sizeof(aluno_t),1,arq) != 1) printf("Erro de escrita!\n"); } }while(strcmp(buffer.nome,"Sair")); fclose(arq); //fecha arquivo }//fecha else //continua... 9 //continuando, na main()... printf("Entre com a média para busca: "); scanf("%d",&media); if(!(arq = fopen(nome,"rb"))) printf("Erro abertura!"); else{ printf("Listando todos os alunos com media acima de %d\n ",media); while(!feof(arq)) { //para no fim do arquivo if(fread(&buffer,sizeof(aluno_t),1,arq) == 1) { if(buffer.media > media) printf("\nAluno %s: Media %d\n",buffer.nome,buffer.media); } } fclose(arq); //fecha } return 0; }//fecha main Arquivos Binários (2), acesso aleatório 10 Arquivos: leitura e gravação sequencial 11 Definição: acessa uma posição sem percorrer sequencialmente o conteúdo que antecede o conteúdo desejado. Motivações: - a posição desejada de leitura ou escrita pode não ser coincidente com a posição corrente do arquivo válida em um certo momento. - a posição corrente de leitura ou escrita pode ser alterada para qualquer posição do arquivo. Arquivos binários: acesso aleatório 12 Três funções de manipulação permitem modificar a posição corrente no arquivo: rewind() - aula passada fseek() ftell() Funções de manipulação de posição 13 Três funções de manipulação permitem modificar a posição corrente no arquivo: rewind() - aula passada fseek() ftell() Funções de manipulação de posição 14 Três funções de manipulação permitem modificar a posição corrente no arquivo: rewind() - aula passada fseek() ftell() Funções de manipulação de posição 15 Exemplo aula passada: dado um arquivo binário com dados de atletas organizados em um tipo estrutura (com nome, altura e idade), ler o nome de um atleta e procurar seus dados no arquivo, imprimindo-os // na main... do { rewind(arq); // reposiciona registro corrente no início do arquivo. encontrado = 0; //indica não encontrado (ainda) printf("Nome do atleta procurado: "); fgets(procurado, MAX_STRLEN, stdin); while(!feof(arq) && !encontrado) //para qdo. acha ou no fim do arquivo if(fread(&buffer,sizeof(atleta_t),1,arq) == 1) if( strcmp(buffer.nome, procurado) == 0) { printf("\nAltura de %s: %.2fm",procurado,buffer.altura); encontrado = 1; // indica que encontrou } } if (!encontrado) printf("\nAtleta nao foi localizado."); printf("\n1-BuscarOutro, 2-Encerrar\n"); scanf("%i",&op); } while(op != 2); // continua... Funções de manipulação de posição - fseek( ) 16 http://en.cppreference.com/w/c/io/fseek Funções de manipulação de posição - fseek( ) 17 Exemplo: dada um arquivo binário com dados de atletas (aula anterior) imprimir na tela os dados do terceiro atleta cadastrado. int main() { atleta_t buffer; FILE *arq; //declaração do ponteiro para arquivo char nome[STR_MAXLEN]; printf("Nome do arquivo (maximo %d caracteres): ", STR_MAXLEN-1); fgets(nome, STR_MAXLEN, stdin); nome[ strlen(nome)-1 ] = '\0'; // remove '\n' lido if( !(arq = fopen(nome,"r+b")) ) // leitura e escrita (os dados permanecem) printf("Erro criacao"); else { // continua... //continua… fseek(arq, 2*sizeof(atleta_t),SEEK_SET); //desloca a partir do inicio if(fread(&buffer,sizeof(atleta_t), 1,arq) == 1) { printf("Nome: %s\n", buffer.nome); printf("Idade: %d\n", buffer.idade); printf("Altura: %.2f\n\n", buffer.altura); } else printf("Erro ao percorrer o arquivo.\n"); fclose(arq); // restante do código é o encerramento do programa } return 0; } //opcionalmente, poderia ler o deslocamento do teclado e armazenar em um int n: // fseek(arq, (n-1)*sizeof(atleta_t),SEEK_SET); // diminui 1 para corrigir o indice de deslocamento Funções de manipulação de posição - fseek( ) 18 Exemplo: dada um arquivo binário com dados de atletas (aula anterior) imprimir na tela os dados do terceiro atleta cadastrado.Funções de manipulação de posição - ftell( ) 19 http://en.cppreference.com/w/c/io/ftell Funções de manipulação de posição - ftell() 20 Exemplo: escreve e lê vetor de inteiros no arquivo binário, indicando quantos bytes foram lidos #include <stdio.h> #include <string.h> #include <stdlib.h> #define NUMEL 5 int main( ) { FILE *arq; char nome[16]; int vetor[NUMEL]; int cont, valor; printf("Nome do arquivo: "); scanf("%s", nome); // n�ao aceita espa�cos //continua... http://en.cppreference.com/w/c/io/ftell Funções de manipulação de posição - ftell() 21 Exemplo: escreve e lê vetor de inteiros no arquivo binário, indicando quantos bytes foram lidos //continuando… // escrita do vetor if(!(arq = fopen(nome,"wb"))) // abre para escrita printf("Erro na abertura\n"); else { printf("Entre %d valores inteiros\n", NUMEL); for (cont = 0; cont < NUMEL; cont++) { scanf("%d", &valor); fwrite(&valor,sizeof(valor), 1 ,arq); } fclose(arq); //fecha arquivo } //continua... http://en.cppreference.com/w/c/io/ftell Funções de manipulação de posição - ftell() 22 Exemplo: escreve e lê vetor de inteiros no arquivo binário, indicando quantos bytes foram lidos //continuando… // leitura do vetor if(!(arq = fopen(nome,"rb"))) // abre para leitura printf("Erro na abertura\n"); else { for (cont = 0; cont < NUMEL; cont++) // varre o arquivo { fread(&vetor[cont],sizeof(valor), 1 ,arq); printf("vetor[%d] = %d\n", cont, vetor[cont]); printf("bytes lidos = %li\n", ftell(arq)); //signed long int (li) } fclose(arq); } return 0; } http://en.cppreference.com/w/c/io/ftell Lembrando do exercício da aula passada: dados de atletas. Programa 5: Faça um programa para atualizar a idade de determinado atleta no arquivo binário, cujo nome foi lido via teclado. Arquivos binários: exercício (programa 5) #define MAX_STRLEN 31 typedef struct atleta_st { char nome[MAX_STRLEN]; int idade; float altura; } atleta_t; 23 // Programa 5 int main() { atleta_t buffer; FILE *arq; //declaração do ponteiro para arquivo char nome[STR_MAXLEN], procurado[MAX_STRLEN]; int encontrado, numLidos, op; //numLidos guarda quantas estruturas foram lidas de arq printf("Nome do arquivo (maximo %d caracteres): ", STR_MAXLEN-1); fgets(nome, STR_MAXLEN, stdin); nome[ strlen(nome)-1 ] = '\0'; // remove '\n' lido if( !(arq = fopen(nome,"r+b")) ) // leitura e escrita (os dados permanecem) printf("Erro ao abrir arquivo"); else { // busca e atualiza // continua... Arquivos binários: exemplo (programa 5) 24 // continuando… // busca e atualiza do { rewind(arq); // reposiciona registro corrente no início do arquivo. printf("Nome do atleta procurado: "); fgets(procurado, MAX_STRLEN, stdin); encontrado = 0; //indica não encontrado (ainda) numLidos = 0; //indica numero de estruturas lidas do arquivo while(!feof(arq) && !encontrado) //para qdo. acha ou no fim do arquivo if(fread(&buffer,sizeof(atleta_t),1,arq) == 1) if( strcmp(buffer.nome, procurado) == 0) { atualizaIdade(arq, buffer, numLidos); encontrado = 1; } numLidos++; } printf("\n1-BuscarOutro, 2-Encerrar\n"); scanf("%i",&op); } while(op != 2); fclose(arq); // restante do código é o encerramento do programa Arquivos binários: exemplo (programa 5) 25 // atualiza idade (v1): desloca a partir do inicio do arquivo numElemLidos*sizeof(atleta_t) void atualizaIdade(FILE* arquivo, atleta_t buffer, int numElemLidos) { printf("\nIdade cadastrada %d",buffer.idade); printf("\nInforme alteração da idade: "); scanf("%d",&buffer.idade); // posiciona no lugar anterior à leitura, usando o // contador de elementos lidos até o momento a partir do inicio do arquivo fseek(arq, numElemLidos*sizeof(atleta_t),SEEK_SET); //substitui, verificando se gravação foi bem sucedida if(fwrite(&buffer,sizeof(atleta_t),1,arq) != 1) printf("\nErro de gravacao!!!\n"); } Arquivos binários: exemplo (programa 5) 26 // atualiza idade (v2): desloca a partir da posicao corrente, “voltando” uma posição void atualizaIdade(FILE* arquivo, atleta_t buffer) { printf("\nIdade cadastrada %d",buffer.idade); printf("\nInforme alteração da idade: "); scanf("%d",&buffer.idade); // posiciona no lugar anterior à leitura, usando // deslocamento negativo a partir da posição corrente fseek(arq, -sizeof(atleta_t),SEEK_CUR); //substitui, verificando se gravação foi bem sucedida if(fwrite(&buffer,sizeof(atleta_t),1,arq) != 1) printf("\nErro de gravacao!!!\n"); } Arquivos binários: exemplo (programa 5) 27 Agora faça um programa que crie um arquivo de atletas de forma randômica, onde o código do atleta indica a posição do seu registro no arquivo. Use o mesmo tipo struct definido no exercício anterior. Arquivos binários: exercício #define MAX_STRLEN 31 typedef struct atleta_st { char nome[MAX_STRLEN]; int idade; float altura; } atleta_t; FILE *fopen( “nome”, “modo” ); int fclose( *stream ) ; size_t fwrite( &buffer_letitura , element_size , quant , *stream_escrita); size_t fread( &buffer_escrita , element_size , quant , *stream_leitura ); int fseek( *stream, offset, origin ); // origin : SEEK_SET SEEK_CUR SEEK_END // modos: Cria para escrita (leitura) - w ou w+ Abre para leitura (escrita) - r ou r+ Atualiza arquivo, escrita (leitura) - a ou a+ 28 Arquivos binários: exercício /* Cria um arquivo com dados de uma estrutura com informações de atletas, de forma randômica. */ #include <stdio.h> #include <string.h> #define MAXCOD 10 // codigos dos atletas entre 1 e 10 #define MAXNOME 16 // tamanho do nome do arquivo typedef struct atleta { char nome[31]; int idade; float altura; }atleta_t; void listaarquivo(FILE*); 29 int main ( ) { FILE *arq; int encontrado = 0, op, cod; char nome[MAXNOME]; Atleta_t buffer; printf("Nome do arquivo: "); scanf("%s", nome); // na�o aceita espa�cos if(!(arq = fopen(nome,"w+b"))) //cria ou recria printf("Erro criacao"); else { do { /* TRECHO DE CRIAÇÃO DO ARQUIVO NO SLIDE A SEGUIR*/ } while (op != 2); listaarquivo(arq); fclose(arq); } return 0; } Arquivos binários: exercício do { //coleta dados do usuário e os escreve cod = le_atleta(&buffer); cod = cod - 1; // corrige para o índice de deslocamento no arquivo //ajusta posicao corrente no arquivo fseek(arq,cod*sizeof(atleta_t),SEEK_SET); if (fwrite(&buffer,sizeof(atleta_t),1,arq) != 1) //escreve os dados printf(“Erro na gravacao\n”); // força a gravação física (opcional, a gravaçao seria feita no fclose) fflush(arq); printf("\n1-InserirNovo, 2-Encerrar: "); scanf("%d", &op); } while(op != 2); 30 Arquivos binários: exercício int le_atleta( atleta_t *buffer){ //coleta dados do usuário e os escreve do { // lê código do atleta, com validação printf("Codigo do atleta, entre 1 e %d: ", MAXCOD); scanf("%d", &cod); if (cod < 1 || cod > MAXCOD) printf("\nCodigo deve estar entre 1 e %d:\n", MAXCOD); } while (cod < 1 || cod > MAXCOD); // fflush(stdin) while((c = getchar()) != '\n' && c != EOF) ; /* limpa stdin */ printf("Nome: "); fgets(buffer->nome, 30, stdin); printf("Idade: "); scanf("%d",&buffer->idade); printf("Altura: "); scanf("%f",&buffer->altura); return cod; } 31 Arquivos binários: exercício void listaarquivo(FILE *arq) { atleta_t buffer; rewind(arq); //retorna ao início, pois posição corrente pode ser outra printf("-----Comeco da listagem-----\n"); while(!feof(arq)) { // enquanto não chegou no final /* testa leitura, para não considerar a tentativa final, que lê EOF*/ /* Descarta registros que contém zero na idade */ if(fread( &buffer, sizeof(atleta_t), 1, arq) == 1 && buffer.idade != 0) { printf("Nome: %s\n",buffer.nome); printf("Idade: %d\n",buffer.idade); printf("Altura: %.2f\n\n",buffer.altura); } } printf("-----Fim da listagem-----\n"); } 32
Compartilhar