Solved

Using ANSI C how to Read a .csv file

Posted on 2016-10-31
10
133 Views
Last Modified: 2016-11-01
I am using a bash shell script to parse a .csv file to create a text file that I read using ANSI C to fill some arrays.  I would like to learn how to read the .csv file just using C.  I only need the last 5 columns of the .csv file.  The .csv file has a one line descriptive header that needs to be skipped,  I have attached a modified version of the C code as well as the .csv file.
DataFile.c
CSVFile.csv
0
Comment
Question by:dwortman
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
10 Comments
 
LVL 19

Expert Comment

by:simon3270
ID: 41867146
You could use a modified scanf to read the CSV entries.  Putting a "*" after the % in a match omits that bit of data.  You can also match the commas between the fields in the scanf string (no need to have spaces).

Reading directly from the csv file:
    fscanf(InputFile, "%*12[0-9/],%*d,%*3[A-Z],%*f,%*f,%*f,%f,%f,%f,%f,%f\n", &A_Array[i], &B_Array[i], &C_Array[i], 
									  &D_Array[i], &E_Array[i]);

Open in new window


The first field matches 12 characters of 0 to 9 or slash, matching the initial date field.  an alternative could be
    "%*d/%*d/%*d,
Similarly, the %*3[A-Z] matches the timezone field.
The next three %*f miss out the next three floating point values.
The last 5 %f collect the values you want.

To skip the header line, you could have something like this, just before your "for i" loop:
    fscanf(InputFile, "%*s\n")
0
 
LVL 34

Expert Comment

by:sarabande
ID: 41867222
fscanf is a dangerous function if you can't guarantee the input file is always valid.

you better read the file line by line and parse the input either by using strtok or by stepping from one delimiter to the next.

#include stdio.h

#define MAX_LINE 1024
#define MAX_TOKEN 256

int main(int nargs, char** szargs)
{
      FILE * pfile = NULL;
      char    buf[MAX_LINE] = { 0 };   // always use a sufficient maximum size 
      int nlines = 0;
      char * pbuf;
      

      if (nargs != 2) return -1;  //error no file path given
      pfile = fopen(szargs[1], "rt");
      if (pfile == NULL) return -2;  // file doesn't exist or already opened exclusively

      while (pbuf = fgets(buf, sizeof(buf), pfile))
      {
             char * p = pbuf;
             int ntoken = 0;
            
             while ((p=strchr(p, ';')) != NULL || (p = strchr(p, '\n)) != NULL)
             {
                   int     len = p - pbuf;
                   char  sztoken[MAX_TOKEN];
                   
                   if (len >= MAX_TOKEN) return -3;  // token too Long
                   strncpy(sztoken, pbuf, len);
                   // do something with sztoken
                   // for example copy it into table[nlines][ntoken];
                   pbuf = p+1;
                   ++ntoken;
              }
              ++nlines;
      }
      fclose(pfile);     
      return 0;        
}

Open in new window


note, the above is not tested.

Sara
0
 
LVL 40

Expert Comment

by:evilrix
ID: 41867372
It's worth noting that parsing out CSV file is actually quite complicated because there are various different flavours of CSV and so you need to know how to correctly handle the flavour you are using. You'd probably be better of not re-inventing the wheel and using a purpose built library, such a libcsv.

https://sourceforge.net/projects/libcsv/
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 19

Expert Comment

by:simon3270
ID: 41867464
I guess there are potential problems with fscanf, but the only data being read here is floating point values - all that will happen with a malformed line is that the scanf will fail to match the line so will not return the value 11 (the number of matched fields).   Adding a check for a return code of 11 would be sensible here.  Problems tend to happen with strings, but the only 2 here are length-limited in the scanf format, and are anyway discarded. fscanf() also does the format conversion for you, so you don't have to add strtof() calls to convert the strings that strtok() returns.

The format seems to pretty simple here - no embedded quotes, not complex data structures, just simple values separated by commas. Using a library might be overkill (and some environments may have policies against using extra libraries), and rolling your own is often a useful learning exercise.
0
 

Author Comment

by:dwortman
ID: 41868430
simon3270,

I like the way you are approaching this problem because I can basically understand it.  However, when I compile it I get the following errors:  (Please see attached file with my comments).
CVSData.docx
0
 

Author Comment

by:dwortman
ID: 41868640
I found a syntax error in my code.  I need to check things out and will get back to close this ticket out.

Thanks
0
 
LVL 19

Accepted Solution

by:
simon3270 earned 500 total points
ID: 41868666
Have you still got the backslash at the end of the first part of the line?  You don't need it (you are already within parentheses, you don't need to tell the compiler that the line hasn't finished!)  I think what's happened is that you have a space after the \ - if you have a \, it must be the last thing on the line.

As for the complaint about "]" in your comment, put [code] before the line of code, and [/code] after it.  I found that the easiest way when sending you the updated line.  An alternative would be to change all of the [i] to []i] - that stops the text interpreter from treating your [i] as an instruction to start using italics, and just treats it as a string of 3 characters.

(Edit - took me a while to write this comment so that the square brackets came out right - didn't spot that you'd already corrected it!)
0
 

Author Comment

by:dwortman
ID: 41868735
simon3270,

The only problem now is that the 1st is not being skipped.  What you suggested to skip the first line looks like it should work.


Thanks
0
 

Author Comment

by:dwortman
ID: 41868914
simon3230,

I got it figured out.

Thanks for the help.
0
 

Author Closing Comment

by:dwortman
ID: 41868915
Thanks for the help.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question