1

I am trying to read a CSV file of the following format:

5,455,78,5
12245,4,78
1,455,4557,1,8,9

I have managed to open the file but I have no idea how to interpret the data. All the data is written in the first column, but I do not know how many rows there are or how many entries there is in each row. This is my code for opening the file.

    printf("File chosen is: %s", file);
    
    int p = 0;
    
    FILE *myFile = NULL;
    
    myFile = fopen(file, "r");
    
    if (myFile == NULL)
    {
        exit(1);
    }
    
    if (myFile != NULL)
    {
        printf("\n\nFile read successfully");
    }
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 4
    Try `fgets()`. It reads one line at a time, provided the buffer is large enough. Also remember to `fclose()` the file when you don't need it any more. – pmg Apr 07 '20 at 11:13
  • 1
    https://stackoverflow.com/questions/12911299/read-csv-file-in-c check whether this link solve your issue – Vishnu CS Apr 07 '20 at 11:15
  • Does your CSV file have lines with differing numbers of fields? – chqrlie Mar 26 '23 at 14:59

4 Answers4

2

This should parse your csv. After opening you file, read each line using fgets. Loop through until fgets returns NULL which indicates no line could be read and you reached the end of your file. Use strtok to parse your line from fgets using the comma as your delimiter.

#include <stdio.h>  // file handling functions
#include <stdlib.h> // atoi
#include <string.h> // strtok

...

    char buffer[80];
    while (fgets(buffer, 80, myFile)) {
        // If you only need the first column of each row
        char *token = strtok(buffer, ",");
        if (token) {
            int n = atoi(token);
            printf("%d\n", n);
        }

        // If you need all the values in a row
        char *token = strtok(buffer, ",");
        while (token) { 
            // Just printing each integer here but handle as needed
            int n = atoi(token);
            printf("%d\n", n);

            token = strtok(NULL, ",");
        }
    }

...
fuentesj
  • 154
  • 7
1

Thank you for posting some code, but you don't mention what you wish to do with your data once you read it in.

I'll give you some pointers:

Use an array of known size to read your data into from the file and buffer it for processing. Run this in a loop. e.g.

  char buffer[1000];

  while (fgets(buffer, sizeof (buffer), myFile))
  {
    char *data = strtok(buffer, ",");

    while (data !=NULL)
    {
        printf("Data %s\n", data);
        /* Further processing of data */

        data = strtok(NULL, ",");
    }
  }

  fclose(myFile);

Process that buffer using strtok to separate out your strings. The token is the data delimiter which should be ',' but I'm not clear on whether you also have a newline character in there, but it needs to be consistent.

Handle your strings returned above.

ChrisBD
  • 9,104
  • 3
  • 22
  • 35
  • I want to sort the data, by using a bubble sort, merge sort and q-sort. I will use a timing function to determine the time each sorting methods takes to sort an array of the data received from the file. – Meghan van Deventer Apr 08 '20 at 11:14
  • @ChrisBD What is the purpose of this line `data = strtok(NULL, ",");` ? Why are you trying to tokenize a `NULL`? – Mehdi Charife Mar 26 '23 at 01:02
  • Actually you should have asked me why I wasn't looping through calling `data-strtok(NULL,",");` until data was `NULL`. `strtok` is called once on the data string being tested and then repeatedly called with `NULL` supplied until result is `NULL`. If you pass a non-NULL value it will restart from the beginning of the string being tested. – ChrisBD Mar 26 '23 at 14:43
  • `strtok()` is inappropriate for parsing CSV files if any of the fields may be empty as it will consider any sequence of separators as a single separator. – chqrlie Mar 26 '23 at 14:57
1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* getfield(char* line, int num)
{
    const char* tok;
    for (tok = strtok(line, ",");
        tok && *tok;
        tok = strtok(NULL, ",\n"))
    {
        if (!--num)
            return tok;
    }
    return NULL;
}

int main()
{
    FILE *stream = fopen("yourfile.csv", "r");
    int i = 0;
    int j = 0;
    printf("Choose a line to be given its elements: ");
    scanf("%d", &j);
    char line[1024];
    while (fgets(line, 1024, stream))
    {
        char* tmp = _strdup(line);
        i++;
        printf("Element %d would be %s\n", i, getfield(tmp, j));
        free(tmp);
    }
}
Amurg
  • 27
  • 1
  • 6
0

If the file contains lines with lists of numbers, here is a simple parser:

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

// return the number of integer in the line, accept empty fields as 0
int parse_line(const char *line, int *array, int len) {
    const char *p = line;
    char *endp;
    int i = 0;

    while (i < len) {
        long n = strtol(p, &endp, 10);
        if (n > INT_MAX) n = INT_MAX;
        if (n < INT_MIN) n = INT_MIN;
        if (*endp == ',' || *endp == ';' || *endp == '\n')
            endp++;
        else
            break;
        array[i++] = n;
        p = endp;
    }
    return i;
}

int main(int argc, char *argv[]) {    
    FILE *myFile = stdin;
    if (argc > 2) {
        const char *file = argv[1];
        printf("File chosen is: %s\n", file);
        myFile = fopen(file, "r");
        if (myFile == NULL) {
            fprintf(stderr, "cannot open %s: %s\n", file, strerror(errno));
            return 1;
        }
    }
    char line[100];
    int array[50];
    while (fgets(line, sizeof line, myFile)) {
        int n = parse_line(line, array, sizeof(array) / sizeof(array[0]));
        for (int i = 0; i < n; i++)
            printf("%d%c", array[i], ",\n"[i == n - 1]);
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189