In this application we have two scenarios where we read CSV files. First to read Students data and second to read books data. Students need to provide student id to login application. We read the students data from csv file and compare the student id. Also, we read large set of books data from csv file.
Sample student csv data:
Sample books csv data:
The header file loadCsvData.h is written to load csv files student data and books data. There are four main functions which reads the files.
static int getStudentID(char stuId[MAX_ID], struct stuProfile *st);
static int loadStuValues(char *line, char *sFields[STU_COL_NUM]);
int readBooks();
static int loadBookValues(char *line, char *lFields[BK_COL_NUM]);
int getRowCount(FILE *fpl);
First two functions static int getStudentID(char stuId[MAX_ID], struct stuProfile *st) and static int loadStuValues(char *line, char *sFields[STU_COL_NUM]) loads student data. Let's breakdown these functions.
Function getStudentID(char stuId[MAX_ID], struct stuProfile *st): This function compares the student id passed in the paraments with the student data read and if student id found, it will initialize the stuProfile structure pointer by student information.
- Line 49: fps = fopen(STU_DATA_FILE, "r") reads the csv file in read mode.
- Line 58: while (!feof(fps)) loop reads the file line by line until the end of the file is reached.
- Line 61: if(fgets(inBuffer, BUFFER_SZ-1, fps)==NULL) break; reads the line from the file into the buffer. The loop will break if end of the file is reached.
- Line 65 and 69: if(++rowNum==1) continue; and if(strlen(inBuffer)==0) continue; skips the first header data and empty lines.
- Line 72: if(loadStuValues(inBuffer,sFields)==FAIL){This call function loadStuValues() to read each columns values from the line. The parameter sFields is character pointer to array of string equal to number of columns. The size of the array must be equal to number of columns in csv file. After reading columns value, function will assign it to sFields pointer variable.
- Line 78: if(strcmp(sFields[ID],stuId)==0) it compares the student id passed in the parameter to file data. If student id exits, followings line will initialize structure stuProfile elements.
static int getStudentID(char stuId[MAX_ID], struct stuProfile *st){
FILE *fps;
// char* array will point to fields
char *sFields[STU_COL_NUM];
int err_count = 0;
fps = fopen(STU_DATA_FILE, "r");
if(fps == NULL) {
//printf("Error opening file: %d\n",errno);
return(FAIL);
}
char inBuffer [BUFFER_SZ];
long rowNum = 0L;
while (!feof(fps)) {
// load line into static buffer
if(fgets(inBuffer, BUFFER_SZ-1, fps)==NULL)
break;
// skip first line (headers)
if(++rowNum==1)
continue;
// jump over empty lines
if(strlen(inBuffer)==0)
continue;
// set pFields array pointers to null-terminated
//string fields in inBuffer
if(loadStuValues(inBuffer,sFields)==FAIL){
err_count++;
if(err_count > MAX_ERROR_NUM)
break;
} else {
//Compare Student ID
if(strcmp(sFields[ID],stuId)==0){
strcpy(st->stuID,sFields[ID]);
strcpy(st->fName,sFields[fNAME]);
strcpy(st->lName,sFields[lNAME]);
strcpy(st->faculty,sFields[FACULTY]);
fclose(fps);
return PASS;
}
}
}
fclose(fps);
return FAIL;
}
Function loadStuValues(char *line, char *sFields[STU_COL_NUM]): This function reads the column value separated by csv. To include the comma value inside the column we will user enclose the column value by double inverted quotation. - Line 97: char delim=','; Initialize delimiter value by comma (,). We can user delimiter other than comma.
- Line 98: if(line == NULL) return FAIL; If the input character buffer value is null, it will return fail flag.
- Line 103: if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1) == '\n') *(line + strlen(line)-1) = '\0'; It chop of last char of input if it is a CR or LF (e.g.Windows file loading in Unix env.). It can be removed if sure fgets has removed both CR and LF from end of line.
- Line 106: char *cptr = line; This declares a character pointer and initializes it to point to the start of the line.
- Line 111: sFields[fld]=cptr; This declares a character pointer and initializes it to point to the start of cptr variable. sFields[fld] is a string which represent the column values. At this line we can consider sFields[0] has value of whole line.
- Line 112 to 126: while((ch=*cptr) != '\0' && fld < STU_COL_NUM) It loop through each character of string cptr until it reaches end of line. Inside while loop, we check opening quote ("), closing quote ("), and comma (,) value in each character and if found will split string by assigning null character ('\0'). Each time adding null character we will increment the index of array sFields and continue loop. At the end array sFields[0] is equal to first column, sFields[1] is equal to second column and so on.
- Line 128 to 131: It will verify the number of columns found in the file and the required number of columns.
- After reading line successfully, the function ends by returning true flag.
static int loadStuValues(char *line, char *sFields[STU_COL_NUM]){
char delim=',';
if(line == NULL)
return FAIL;
// chop of last char of input if it is a CR or LF
//(e.g.Windows file loading in Unix env.)
// can be removed if sure fgets has removed both CR
//and LF from end of line
if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1) == '\n')
*(line + strlen(line)-1) = '\0';
char *cptr = line;
int fld = 0;
int inquote = FALSE;
char ch;
sFields[fld]=cptr;
while((ch=*cptr) != '\0' && fld < STU_COL_NUM){
if(ch == '"') {
if(! inquote){
sFields[fld]=cptr+1;
}else {
*cptr = '\0';// zero out quote and jump over it
}
inquote = ! inquote;
} else if(ch == delim && ! inquote){
*cptr = '\0';// end of field, null terminate it
sFields[++fld]=cptr+1;
}
cptr++;
}
if(fld > STU_COL_NUM-1){
return FAIL;
} else if (fld < STU_COL_NUM-1){
return FAIL;
}
return PASS;
}
No comments:
Post a Comment