ccsvfopenstrtokgetc

How to read values from a CSV file with fgets() without skipping data?


I'm trying to read a CSV file where I have just double values separated with a comma. I'm using the char *fgets(char *str, int n, FILE *stream) function to read the rows. In the code, to finish the do-while loop, I'm using the getc() method to read the next char, to find out if I've read the end of the file. The problem is, getc() method read the first character from the next line, so I'm losing data (as the first number in the next line loses one digit). As you can see, apart from the first row, all the first column entries lost their first characters.

What should I use to control my while loop? Or is there another method that I should use to read data from CSV files? Thank you very much

Data from my_file.csv:

3.0000,4.0000,5.0000,6.0000,7.0000
6.0000,5.0000,4.0000,3.0000,2.0000
9.0000,6.0000,3.0000,0.0000,-3.0000
12.0000,7.0000,2.0000,-3.0000,-8.0000
15.0000,8.0000,1.0000,-6.0000,-13.0000
18.0000,9.0000,0.0000,-9.0000,-18.0000

Actual output:

[enter image description here][1]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getData(char *buff);

int main() {

    char folder_addr[] = "C:\\my_file.csv";

    FILE *fp = fopen(folder_addr, "r");
    do  {
        char buff[1024];
        fgets(buff, 1024, (FILE*)fp);
        printf(buff);
        getData(buff);
    } while ((getc(fp)) != EOF);

    return 0;
};

void getData(char *buff){
    char *token = strtok(buff, ",");
    //printf("First value:  %s\n", token);

    while (token != NULL)   {
        //printf("First value:  %s\n", token);
        token = strtok(NULL, ",");
    }
}


  [1]: https://i.sstatic.net/fQzw1.jpg

Solution

  • The best thing to do is to just do a while(fgets()) instead of a do-while. I would not say that peeking a single char is the best method here.

    For those cases where it is a reasonable option (if such a case exists) to do so, you can do a fseek(fp, -1, SEEK_CUR) to go back one step. It is a tiny bit ugly, but not to bad and it gets the job done. You would need to reorder a little bit like this:

    while ((getc(fp)) != EOF) {
        fseek(fp, -1, SEEK_CUR);
        char buff[1024];
        fgets(buff, 1024, (FILE*)fp);
        printf(buff);
        getData(buff);
    } 
    

    However, do note that the fseek is not guaranteed to work if the stream is not seekable, such as pipes. It is better to use ungetc. Same principle. You put the character you just read back in the stream.

    A similar method is this:

    int c;
    while ((c = getc(fp)) != EOF) {
        char buff[1024];
        buff[0]=c;
        fgets(&buff[1], 1023, (FILE*)fp);
        printf(buff);
        getData(buff);
    } 
    

    You should also change printf(buff) to puts(buff)