Solved

Using ANSI C how to Read a .csv file

Posted on 2016-10-31
10
80 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
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 33

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
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
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

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

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…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

777 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