Home > Enterprise >  C - Read input from text file (int,string,int,int)
C - Read input from text file (int,string,int,int)

Time:02-12

First of all sorry for any english error. So, I have this data in a .txt file

Codigo,Produto,StockMinimo,StockAtual
1,Couro,300,1000
2,Tecido,250,2000
...

I want to skip the first line and read only the integers to a struct

I'm using the bellow function to count the line of the file:

int nrLinhasFicheiro(char *filename){
    char ch;
    FILE *file;
    file = fopen(filename, "r");
    int linhas = 0;
    if (file != NULL) {
         for (ch = getc(file); ch != EOF; ch = getc(file)) 
        if (ch == '\n')  
            linhas = linhas   1; 
    }
    fclose(file);
    return linhas - 1;
}

and this one to read the file to the struct "Stock" :

void carregarStock(Stock *stock, char *nomeFicheiro){
    int i = 0;
    int codigo; //stores "codigo" values
    char stringFake[40], *storeProduto; //variables to store first line and "Produto" string
    int minimo, quantidade;
    
    FILE *fp = fopen(nomeFicheiro, "r");
    
    int numeroLinhas = nrLinhasFicheiro(nomeFicheiro);
    
    if (fp != NULL){
       
        if(numeroLinhas >0){
            fscanf(fp, "%s",stringFake);//skip first line
            
            while(i< numeroLinhas){
                fscanf(fp, "%d,%s ,%d,%d", &codigo, storeProduto, &minimo, &quantidade);
                //fscanf(fp, "%d,%s %d,%d", &codigo, storeProduto, &minimo, &quantidade);  also tried this and don't work
                
                if(codigo==1){
                    stock->minStockCouro = minimo;
                    stock->couroStock = quantidade;
                }else if(codigo==2){
                    stock->minStockTecido = minimo;
                    stock->tecidoStock = quantidade;
                }else if(codigo==3){
                    stock->minStockBorracha = minimo;
                    stock->borrachaStock = quantidade;
                }else if(codigo==4){
                    stock->minStockCordoes = minimo;
                    stock->cordoesStock = quantidade;
                }else if(codigo==5){
                    stock->minStockPalmilhas = minimo;
                    stock->palmilhasStock = quantidade;
                }   
                i  ;
            }
            
        }else{
            puts("Error");          
        }      
    }else{
        puts(MSG_ERRO_LER_FICHEIRO);
    }
    fclose(fp);
}

Function to print the struct:

void mostrarStock(Stock stock){
    puts("==============  Stock : =============\n");
    puts("Codigo | Produto | Stock Minimo | Stock Atual\n");
    printf("1\tCouro\t\t%d\t\t%d\n", stock.minStockCouro, stock.couroStock);
    printf("2\tTecido\t\t%d\t\t%d\n", stock.minStockTecido, stock.tecidoStock);
    printf("3\tBorracha\t%d\t\t%d\n", stock.minStockBorracha, stock.borrachaStock);
    printf("4\tCordões\t\t%d\t\t%d\n", stock.minStockCordoes, stock.cordoesStock);
    printf("5\tPalmilhas\t%d\t\t%d\n", stock.minStockPalmilhas, stock.palmilhasStock);

}   

This is how i call the function in main:

int main(int argc, char** argv) {
    
    char *nomeFicheiro1 = "tabela_stocks.txt";
    Stock stock;
    carregarStock(&stock, nomeFicheiro1);
    mostrarStock(stock);
    
    return (EXIT_SUCCESS);
}

The function to print the struct doesn't print. I guess the error is in

fscanf(fp, "%d,%s ,%d,%d", &codigo, storeProduto, &minimo, &quantidade);

What am I doing wrong?

CodePudding user response:

You could create a helper function to read out the two integers from one line.

bool get_two(FILE *stream, int* a, int* b) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", a, b) == 2;
}

You then just need to call that 5 times.

Example:

#include <stdbool.h>
#include <stdio.h>

typedef struct {
    int couroStock;
    int minStockCouro;
    int tecidoStock;
    int minStockTecido;
    int borrachaStock;
    int minStockBorracha;
    int cordoesStock;
    int minStockCordoes;
    int palmilhasStock;
    int minStockPalmilhas;
} Stock;

bool get_two(FILE *stream, int* a, int* b) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", a, b) == 2;
}

int main() {
    FILE *fp = fopen("tabela_stocks.txt", "r");
    if(fp) {
        Stock s;
        fscanf(fp, "%*[^\n]"); // skip first line

        if(get_two(fp, &s.couroStock, &s.minStockCouro) &&
           get_two(fp, &s.tecidoStock, &s.minStockTecido) &&
           get_two(fp, &s.borrachaStock, &s.minStockBorracha) &&
           get_two(fp, &s.cordoesStock, &s.minStockCordoes) &&
           get_two(fp, &s.palmilhasStock, &s.minStockPalmilhas))
        {
            printf("%d %d\n", s.couroStock, s.minStockCouro);
            printf("%d %d\n", s.tecidoStock, s.minStockTecido);
            printf("%d %d\n", s.borrachaStock, s.minStockBorracha);
            printf("%d %d\n", s.cordoesStock, s.minStockCordoes);
            printf("%d %d\n", s.couroStock, s.minStockCouro);
        }
        fclose(fp);
    }
}

If tabela_stocks.txt contains

Codigo,Produto,StockMinimo,StockAtual
1,Couro,300,1000
2,Tecido,250,2000
3,Borracha,200,500
4,Cordões,500,2000
5,Palmilhas,500,1000

Then the output will be

300 1000
250 2000
200 500
500 2000
300 1000

Since there are so many similarities between the different stocks in your Stock struct, you could break it down into smaller pieces and make a struct only holding information about one stock:

#include <stdbool.h>
#include <stdio.h>

typedef struct {
    int stock;
    int min_stock;
} Stock;

bool Stock_read(FILE *stream, Stock *s) {
    return fscanf(stream, " %*[^,],%*[^,],%d,%d", &s->stock, &s->min_stock) == 2;
}

void Stock_print(const Stock *s) {
    printf("%d %d\n", s->stock, s->min_stock);
}

With that you could create a Stocks type like this:

typedef struct {
    Stock Couro;
    Stock Tecido;
    Stock Borracha;
    Stock Cordoes;
    Stock Palmilhas;
} Stocks;

bool Stocks_read(FILE *stream, Stocks *s) {
    return
        Stock_read(stream, &s->Couro) &&
        Stock_read(stream, &s->Tecido) &&
        Stock_read(stream, &s->Borracha) &&
        Stock_read(stream, &s->Cordoes) &&
        Stock_read(stream, &s->Palmilhas);
}

void Stocks_print(const Stocks *s) {
    Stock_print(&s->Couro);
    Stock_print(&s->Tecido);
    Stock_print(&s->Borracha);
    Stock_print(&s->Cordoes);
    Stock_print(&s->Palmilhas);
}

and reading and printing would become simpler:

int main() {
    FILE *fp = fopen("tabela_stocks.txt", "r");
    if(fp) {
        Stocks s;
        fscanf(fp, "%*[^\n]"); // skip first line

        if(Stocks_read(fp, &s)) {
            Stocks_print(&s);
        }
        fclose(fp);
    }
}

Looking closer at the Stocks struct you may want to consider using an array instead:

typedef struct {
    Stock stocks[5];
} Stocks;

which would also simplify the rest of the code since you could loop over that array to read and print each Stock.

  • Related