Solved

Using ANSI C how to Read a .csv file

Posted on 2016-10-31
10
50 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 32

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
 
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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
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 recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

757 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now