Read file in C

Asked

Viewed 1,118 times

5

I am doing a project in C, which is necessary to create and read a file. I am having difficulty implementing the reading. In reading I tried to apply fgets(), fscanf() and the fread(). But none worked. Someone suggests something to me?

Thank you in advance.

Follows the code:

main()
{
    //Declaração de variáveis

    Cliente *primeiro = NULL;
    int opcao;

    //Artificio para repetir o programa

    while (opcao != 5)
    {
        //Menu de opcoes

        printf("MENU\n");
        printf("<1> Novo cadastro de cliente \n");
        printf("<2> Listar clientes\n");
        printf("<3> Excluir cadastro de cliente\n");
        printf("<4> Alterar cadastrado de cliente\n");
        printf("<5> Sair");

       //lendo a opcao do menu
        fflush(stdin);
        printf("\nDigite a opcao desejada:");
        scanf("%d",&opcao);



    switch(opcao)
    {
        case 1:

        //Inserindo os clientes
        fflush(stdin);
        system("cls");
        printf("NOVO CADASTRO DE CLIENTE\n");
        primeiro = inserir_cliente(primeiro);
        getch();
        system("cls");
        break;

        case 2:
       //Listando os clientes
        system("cls");
        printf("CLIENTES CADASTRADOS\n");
        listar_cliente(primeiro);
        getch();
        system("cls");
        break;

        case 3:
        //excluir cliente
        system("cls");
        printf("EXCLUIR CLIENTES");
        primeiro = excluir_cliente(primeiro);
        getch();
        system("cls");
        break;

        case 4:
        //açterar informaçoes do cliente
        system("cls");
        printf("ALTERAR INFORMACOES DO CLIENTE");
        alterar_cliente(primeiro);
        getch();
        system("cls");
        break;

        case 5:
        //artificio para sair do programa.
        opcao = 5;
        break;

        default:
        system("cls");
        break;

    }
  }
}

Cliente* inserir_cliente(Cliente *primeiro)
{
    FILE *cli;

    cli = fopen("cadastrocliente.txt","a+");

    if(cli == NULL)
    {
        printf("Arquivo NAO pode ser aberto");
        system("pause");
        return 0;
    }

    Cliente novocliente;
    Cliente *atual = primeiro;
    char identificador = 'F';

    //Lendo as informaçoes do cliente.

    printf("\nNome:");
    fflush(stdin);
    fgets(novocliente.nome,40,stdin);
    printf("\n");

    printf("CPF:",135);
    fflush(stdin);
    fgets(novocliente.cpf,15,stdin);
    printf("\n");

    printf("Codigo:",162);
    scanf("%u",&novocliente.codigo);
    printf("\n");


    //Verificando se o cadastro já existe.

    for(atual=primeiro; atual!=NULL; atual=atual->prox)
    {
        if(atual->codigo==novocliente.codigo)
        {
            identificador= 'V';
            break;
        }
    }
    if(identificador!='V' && (strlen(novocliente.nome)!=1 && strlen(novocliente.cpf)!=1))
    {
        //Alocando os espaços e guardando as informaçoes do cliente.
        Cliente* ClienteNovo=(Cliente*) malloc(sizeof(Cliente));
        strcpy(ClienteNovo->nome,novocliente.nome);
        strcpy(ClienteNovo->cpf,novocliente.cpf);
        ClienteNovo->codigo=novocliente.codigo;
        ClienteNovo->prox=primeiro;


        printf("Cadastro realizado com sucesso.");


        fprintf(cli,"%u\n",novocliente.codigo);
        fprintf(cli,"%s",novocliente.nome);
        fprintf(cli,"%s",novocliente.cpf);

        system("cls");

        printf("Codigo: %u",novocliente.codigo);
        printf("\nNome: %s",novocliente.nome);
        printf("CPF: %s",novocliente.cpf);


        getchar();
        fclose(cli);
        //system("cls");

        printf("\n\nPRESSIONE QUALQUER TECLA PARA VOLTAR AO MENU PRINCIPAL.");
        return ClienteNovo;
    }

     else
    {
        printf("Cadastro INVALIDO",160);
    }

}

void listar_cliente(Cliente* primeiro)
{

    FILE *cli;

    cli = fopen("cadastrocliente.txt","r");

    if(cli == NULL)
    {
        printf("Arquivo NAO pode ser aberto.\n");
        system("pause");
        //return 0;
    }



    Cliente* atual; //Ponteiro para percorrer a lista sem perder a referência do primeiro elemeto da lista.


        //Imprimindo os clientes da lista, e suas respectivas informações.


    for(atual = primeiro; atual != NULL; atual = atual -> prox)
    {
        printf("\n Nome:");
        printf("%s", atual -> nome);
        printf("\n CPF:",162);
        printf("%s", atual -> cpf);
        printf("\n Codigo:");
        printf("%u",atual -> codigo);
        printf("\n\n");

    }

    if(primeiro == NULL)
    {
        printf("\n\nNENHUM CLIENTE CADASTRADO.\n");
    }


    fclose(cli);


    printf("\n\nPRESSIONE QUALQUER TECLA PARA VOLTAR AO MENU PRINCIPAL.");
}

Cliente* excluir_cliente(Cliente* primeiro)
{
    FILE *cli;

    cli = fopen("cadastro.txt","a");

     if(cli == NULL)
    {
        printf("Arquivo NAO pode ser aberto");
        system("pause");
        return 0;
    }

     Cliente *anterior=NULL;// ponteiro para saber o elemento anterior ao elemento atual da lista.
     Cliente *atual=primeiro;//Ponteiro para percorrer a lista sem perder o primeiro elemento da lista.
     unsigned long int codigo=0;


     //Requisitando e lendo o código do cliente a ser excluido.
     printf("\nCodigo do cliente a ser excluido:",162,161);
     fflush(stdin);
     scanf("%u",&codigo);

     //Procurando o cliente na lista

     while(atual!= NULL && atual->codigo!=codigo)
     {
         anterior=atual;
         atual=atual->prox;
     }

     //Mensagem caso o cliente não seja encontrado.

     if(atual==NULL)
     {
         printf("\n Cliente NAO encontrado.",198);
         printf("\n\nPRESSIONE QUALQUER TECLA PARA VOLTAR AO MENU PRINCIPAL.");
         return primeiro;
     }

     //Excluindo o primeiro cliente da lista.

     if(anterior==NULL)
     {
         printf("\n Conteudo EXCLUIDO com sucesso.",163,161);
         primeiro=atual->prox;
     }
     //Excluindo um cliente do meio da lista.
     else
     {
         printf("\n Conteudo excluido com sucesso.",163,161);
         anterior->prox=atual->prox;

     }
     //Desalocando o espaço da memoria.
     free(atual);
     printf("\n\nPRESSIONE QUALQUER TECLA PARA VOLTAR AO MENU PRINCIPAL.");
     return primeiro;

     getchar();
    fclose(cli);

}

void alterar_cliente(Cliente* primeiro)
{
     char nome_substituto[40], cpf_substituto[40];
     unsigned long int codigo;
     Cliente* atual=primeiro;

     //Requisitando e lendo o codigo do cliente a ser alterado.

     printf("\n\nCodigo do cliente a ser alterado:",162);
     fflush(stdin);
     scanf("%u",&codigo);

     //Procurando o cliente na lista.
     while(atual!=NULL && atual->codigo!=codigo)
     {
         atual= atual->prox;
     }

     //Alterando os dados do cliente.

     if(atual!=NULL)
     {
         printf("\nNovo Nome:");
         fflush(stdin);
         fgets(nome_substituto,40,stdin);
         strcpy(atual->nome,nome_substituto);

         printf("\nNovo cpf:",135);
         fflush(stdin);
         fgets(cpf_substituto,40,stdin);
         strcpy(atual->cpf,cpf_substituto);

         printf("\n Dados ALTERADOS com sucesso.");

     }else{
         printf("\n\n Cliente NAO Encontrado",198);
     }

     printf("\n\n\nPRESSIONE QUALQUER TECLA PARA VOLTAR AO MENU PRINCIPAL.");
}
  • There are several parts where you use numbers that will be used in printf, as an example printf("CPF:",135); and printf("\nCodigo do cliente a ser excluido:",162,161); - Because the numbers are there if they won’t be used ever?

1 answer

3

Use fread and fwrite. To use them, you must open the file in binary mode.

The file size is obtained through fseek followed by ftell.

Here is a way to insert or update the client in the file. If the code does not exist, it inserts. If it exists it changes:

// Estrutura que mostra como o cliente é salvo no arquivo.
// Isso é diferente da forma como ele é representado em memória por não haver o ponteiro prox.
// Outras diferenças podem vir a ser possíveis também.
typedef struct {
    char nome[41]; // 40 caracteres mais o terminador nulo.
    char cpf[16]; // 15 caracteres mais o terminador nulo.
    int codigo;
} ClienteArquivo;

void inserir_ou_alterar_cliente_no_arquivo(Cliente* cliente) {
    FILE *arquivo = fopen("cadastrocliente.dat", "a+b");

    if (arquivo == NULL) {
        printf("Arquivo NAO pode ser aberto.\n");
        system("pause");
        return;
    }

    fseek(arquivo, 0L, SEEK_END);
    int tamanho_do_arquivo = ftell(fp);
    int numero_de_registros = tamanho_do_arquivo / sizeof(ClienteArquivo);

    ClienteArquivo lido;

    // Percorre o arquivo até achar a posição aonde o cliente está lá.
    // Ao término, i será o número do registro no qual o cliente está,
    // ou então será o fim do arquivo (numero_de_registros) se o cliente
    // não for encontrado.
    int i;
    for (i = 0; i < numero_de_registros; i++) {
        fseek(arquivo, i * sizeof(ClienteArquivo), SEEK_SET);
        fread(&lido, sizeof(ClienteArquivo), 1, arquivo);
        if (lido.codigo == cliente->codigo) break;
    }

    // Copia os dados do cliente.
    memset(&lido, 0, sizeof(ClienteArquivo)); // Limpa para evitar que eventuais lixos na memória acabem sendo escritos no arquivo.
    strcpy(lido.nome, cliente->nome); // Copia o nome.
    lido.nome[40] = 0; // Força o terminador nulo.
    strcpy(lido.cpf, cliente->cpf); // Copia o CPF.
    lido.cpf[15] = 0; // Força o terminador nulo.
    lido.codigo = cliente->codigo; // Copia o código.

    // Se terminou de percorrer o for e não achou no arquivo, então posiciona no final.
    if (i == numero_de_registros) fseek(arquivo, 0L, SEEK_END);

    // Escreve o cliente.
    fwrite(&lido, sizeof(ClienteArquivo), 1, arquivo);

    fclose(arquivo);
}

Deletion is a little harder as the file size decreases in this case. Also, deleting in the middle of the file would leave holes. The solution is to copy the last record from the file to the position where the deletion occurred and then make the file size diminiur.

void excluir_cliente_no_arquivo(Cliente* cliente) {
    FILE *arquivo = fopen("cadastrocliente.dat", "a+b");

    if (arquivo == NULL) {
        printf("Arquivo NAO pode ser aberto.\n");
        system("pause");
        return;
    }

    fseek(arquivo, 0L, SEEK_END);
    int tamanho_do_arquivo = ftell(fp);

    if (tamanho_do_arquivo != 0) {

        int numero_de_registros = tamanho_do_arquivo / sizeof(ClienteArquivo);

        ClienteArquivo ultimo;

        // Lê o último registro.
        fseek(arquivo, tamanho_do_arquivo - sizeof(ClienteArquivo), SEEK_SET);
        fread(&ultimo, sizeof(ClienteArquivo), 1, arquivo);

        ClienteArquivo lido;

        // Percorre o arquivo até achar a posição aonde o cliente está lá.
        // Ao término, i será o número do registro no qual o cliente está,
        // ou então será o fim do arquivo (numero_de_registros) se o cliente
        // não for encontrado.
        int i;
        for (i = 0; i < numero_de_registros; i++) {
            fseek(arquivo, i * sizeof(ClienteArquivo), SEEK_SET);
            fread(&lido, sizeof(ClienteArquivo), 1, arquivo);
            if (lido.codigo == cliente->codigo) break;
        }

        // Se achou, substitui o registro encontrado com o último e diminui o arquivo.
        if (i < numero_de_registros) {
            fseek(arquivo, i * sizeof(ClienteArquivo), SEEK_SET);
            fwrite(&ultimo, sizeof(ClienteArquivo), 1, arquivo);
            ftruncate(fileno(arquivo), tamanho_do_arquivo - sizeof(ClienteArquivo));
        }
    }
    fclose(arquivo);
}

Finally, you will also need to search for a client in the file and return your data:

ClienteArquivo* procurar_cliente_no_arquivo(int codigo) {
    FILE *arquivo = fopen("cadastrocliente.dat", "a+b");

    if (arquivo == NULL) {
        printf("Arquivo NAO pode ser aberto.\n");
        system("pause");
        return NULL;
    }

    ClienteArquivo *lido = (ClienteArquivo *) malloc(sizeof(ClienteArquivo));

    // Percorre o arquivo até achar a posição aonde o cliente está lá.
    // Ao término, i será o número do registro no qual o cliente está,
    // ou então será o fim do arquivo (numero_de_registros) se o cliente
    // não for encontrado.
    int i;
    for (i = 0; i < numero_de_registros; i++) {
        fseek(arquivo, i * sizeof(ClienteArquivo), SEEK_SET);
        fread(lido, sizeof(ClienteArquivo), 1, arquivo);
        if (lido.codigo == codigo) break;
    }

    // Se não encontrou, desaloca a memória alocada e retorna NULL.
    // Se encontrar retorna um ponteiro para a estrutura alocada. 
    if (i == numero_de_registros) {
        free(lido);
        lido = NULL;
    }

    fclose(arquivo);
    return lido;
}

This function above returns a pointer with the customer data. Later you will need to create a Cliente on the basis of ClienteArquivo returned, since ClienteArquivo has no pointer to the next record. You should also not forget to call the free in the ClienteArquivo returned when you no longer need it. The function will return NULL if you do not find the client with the code sought.

And then you should only manipulate files through these functions. No use fopen, fwrite, fread, fprintf or anything else other than within those three functions above. This way, you leave the parts that manipulate the files directly isolated in these functions, and prevent them from spreading and complicating the rest of the application. If you don’t break this rule, it will make your functions inserir_cliente, listar_cliente, alterar_cliente and excluir_cliente (as well as any others that you need to create) much simpler and less prone to possible programming errors, since you will separate the functions that manipulate file from the functions that manipulate data structures in memory.

Note: these functions are very sensitive regarding the file format! If you create or change the file cadastrocliente.dat By any means other than these three functions, you will end up corrupting your file and driving your program crazy. Whenever you change the format of ClienteArquivo, recommend destroying the previous file to avoid the possibility of manipulating records with wrong formats. And since it is now a binary file, not a text file, I even changed the extension to .txt for .dat. Do not try to manipulate this file in the notepad or treat it as if it were text.

Other tips:

  • Be careful with the fflush(stdin). Your code will not work on linux! Also, if you are on linux, you will have to use system("clear"); instead of system("cls");. See in this link reply how to resolve this and read in the reply comments as well.

  • Do not pass useless parameters on printf. Such as for example: printf("CPF:",135); and printf("\nCodigo do cliente a ser excluido:",162,161);, where the 135, the 162 and the 161 are useless. There are several places where you do this.

  • Use 0 and 1 for false and true, instead of F or V. The main reason is that this is the standard form in C and also the code is easier to read as you would simplify if (identificador == 'V') or if (identificador != 'F') for if (identificador), and would simplify the if (identificador != 'V') or if (identificador == 'F') for if (!identificador).

  • Every time I use fclose, make sure it is used in all possible function paths. In its function excluir_cliente, For example, this did not happen when the client was not found. However, if you only manipulate the file with the above three functions and eliminate file manipulation from all other places, this problem will disappear.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.