C語言實(shí)現(xiàn)讀取CSV文件的方法詳解
1、每一次只能讀取同一種數(shù)據(jù)類型,不能讀取字符串。
2、第次讀取會(huì)返回一個(gè) CSV數(shù)據(jù)結(jié)構(gòu),有源數(shù)據(jù)和二維數(shù)組,行列數(shù)信息
3、可以轉(zhuǎn)換二維數(shù)組,但總大小不能變
123.csv
Month,"CO2 (ppm) mauna loa, 1965-1980",,,CO2 (ppm) mauna loa Jan-65,319.32,1,,, Feb-65,320.36,2,,, Mar-65,320.82,3,,, Apr-65,322.06,4,,, May-65,322.17,5,,, Jun-65,321.95,6,,,
頭文件 read_csv_data.h
#include <stdio.h> #include <memory.h> // for memset #include <stdlib.h> // for malloc, free #include <string.h> // for strtok //fgets函數(shù)讀取的最大字節(jié)數(shù) #define MAX_LINE_SIZE 1024 //字符串分割結(jié)構(gòu) struct str_split { int count; char *str; char **str_array; }; //可變數(shù)據(jù)類型 typedef union dtype_u{ long int s32; char s8; short int s16; unsigned char u8; unsigned short int u16; unsigned long int u32; float f32; double f64; } Dtype; //CSV文件結(jié)構(gòu) struct csv_s{ Dtype **darray; //二維數(shù)組 int drow; int dcol; int dnum; //總有多少個(gè) Dtype data[]; }; enum{ S8, S16, S32, U8, U16, U32, F32, F64, DEF = S32 }; /* 釋放CSV文件結(jié)構(gòu),使用方法,查看testFile() */ void FreeCsvData(struct csv_s **csv_ptr); /* 對(duì)CSV數(shù)據(jù)進(jìn)行二維轉(zhuǎn)換,生成新的二維數(shù)據(jù)。使用方法,查看testFile() */ int setNewArray( struct csv_s *tt, int row, int col); /* 讀取CSV文件數(shù)據(jù),生成CSV結(jié)構(gòu)。使用方法,查看testFile() csvFilePath:文件路徑 delimiter: 分割符 skiprows: 跳過頭N行 ColumnList:選把指定列,從0列開始, dclass: 數(shù)據(jù)類型 */ struct csv_s *ReadCsvData(char* csvFilePath, char delimiter, int skiprows, char *ColumnList, int dclass);
源碼 read_csv_data.c
#include "read_csv_data.h" int str_split_func(struct str_split *split, char * src, char delimiter) { int count = 0; char *pchar, **ptr; if ( NULL != split ) { memset(split, 0, sizeof(struct str_split)); } if(NULL == split || NULL == src || src[0] == '\0') { return 0; } split->str = strdup(src); if(NULL == split->str) { return 0; } count = 1; pchar = src; while('\0' != *pchar) { if (delimiter == *pchar) { count++; } pchar++; } split->str_array = (char **)malloc(count*sizeof(char*)); if(NULL == split->str_array) { return 0; } split->count = count; ptr = split->str_array; *ptr = split->str; pchar = split->str; while('\0' != *pchar && count > 1) { if (delimiter == *pchar) { ptr++; *ptr = pchar+1; *pchar = '\0'; count--; } pchar++; } return 0; } int str_split_free(struct str_split *split) { if(split == NULL) { return 0; } if(split->str!=NULL) { free(split->str); split->str=NULL; } if(split->str_array != NULL) { free(split->str_array); split->str_array=NULL; } return 0; } //計(jì)算csv文件中的總大?。ㄗ止?jié)) int GetTotalSize(FILE * fp) { if(fp==NULL){ return -1; } fseek(fp,0,SEEK_END); return ftell(fp); } //計(jì)算csv文件中的總行數(shù) int GetTotalLineCount(FILE * fp) { int i = 0; char strLine[MAX_LINE_SIZE]; fseek(fp,0,SEEK_SET); while (fgets(strLine, MAX_LINE_SIZE, fp)) i++; fseek(fp,0,SEEK_SET); return i; } //計(jì)算csv文件中的總列數(shù)(以第一行的列數(shù)為基準(zhǔn)) int GetTotalColCount(FILE * fp, char delimiter) { int i = 0; char strLine[MAX_LINE_SIZE]; struct str_split tss; fseek(fp,0,SEEK_SET); char *str=NULL; str = fgets(strLine, MAX_LINE_SIZE, fp); if (str) { str_split_func(&tss, strLine, delimiter); i = tss.count; str_split_free(&tss); } return i; } // 通過指針*giCsvData給數(shù)據(jù)動(dòng)態(tài)分配內(nèi)存空間 int strToData(Dtype *d, char *str, int dtpye) { switch(dtpye){ case S8: *((char *)d) =(char) strtol(str,NULL,10); break; case S16: *((short int *)d) =(short int) strtol(str,NULL,10); break; case S32: *((long int *)d) =(long int) strtol(str,NULL,10); break; case U8: *((unsigned char *)d) =(unsigned char ) strtol(str,NULL,10); break; case U16: *((unsigned short int *)d) =(unsigned short int) strtol(str,NULL,10); break; case U32: *((unsigned long int *)d) =(unsigned long int) strtol(str,NULL,10); break; case F32: *((float *)d) =(float) strtod(str,NULL); break; case F64: *((double *)d) =(double) strtod(str,NULL); break; default: printf("讀取數(shù)據(jù)類型不對(duì)\n"); return -1; } return 0; } // 對(duì)CSV結(jié)構(gòu)中的二維數(shù)組進(jìn)行轉(zhuǎn)換 int setNewArray( struct csv_s *tt, int row, int col) { int i; //CSV結(jié)構(gòu)不NULL if(tt == NULL)return -1; //新的行列總個(gè)數(shù),與舊的數(shù)據(jù)個(gè)數(shù)不等 if(row * col != tt->dnum)return -2; Dtype **darray=(Dtype **)malloc( sizeof(Dtype *[row]) ); //分配內(nèi)存空間失敗,出錯(cuò)的可能性不大 if(!darray)return -3; if(tt->darray)free(tt->darray); tt->drow = row; tt->dcol = col; tt->dnum = row * col; tt->darray = darray; for(i=0; i<row; i++){ tt->darray[i]=(Dtype *)(tt->data+i*col); } return 0; } // 釋放動(dòng)態(tài)數(shù)據(jù)內(nèi)存 void FreeCsvData(struct csv_s **csv_ptr) { if(*csv_ptr){ if((*csv_ptr)->darray) free((*csv_ptr)->darray); free(*csv_ptr); } *csv_ptr=NULL; return ; } // 從csv文件中讀取數(shù)據(jù) struct csv_s *ReadCsvData(char* csvFilePath, char delimiter, int skiprows, char *ColumnList, int dclass) { /* delimiter:分割符 dtype:數(shù)據(jù)類型,多個(gè)數(shù)據(jù)類型使用逗號(hào)分割,從第一列到最后一列開始一一對(duì)應(yīng)。默認(rèn)其他的是float 類型。 例:有5列 dtype=“str, str, str” 則前三列為string類型,后兩列為float類型 skiprows:跳過開頭N行 ColumnList:取N列數(shù)據(jù)。 例:"2,1,3",取第 2,1,3列數(shù)據(jù)返回 */ FILE* fCsv=NULL; int rowTotal=0; int colTotal=0; struct str_split tss; struct csv_s *temp_csv=NULL; int cur_ptr=0; char strLine[MAX_LINE_SIZE]; int i; int j; //獲取指定列 int t_column_list=0; int *t_column_list_ptr=NULL; if(access(csvFilePath, 0)<0){ printf("%s 文件不存在\n", csvFilePath); goto label_error; } // 打開文件 fCsv = fopen( csvFilePath, "r" ); if( fCsv==NULL ) { printf("open file %s failed",csvFilePath); goto label_error; } rowTotal = GetTotalLineCount(fCsv); colTotal = GetTotalColCount(fCsv, delimiter); //獲取指定列 if(ColumnList==NULL){ t_column_list=colTotal; t_column_list_ptr = malloc(sizeof(t_column_list) * t_column_list); for(i=0;i<tss.count;i++){ t_column_list_ptr[i]=i; } }else{ str_split_func(&tss, ColumnList, ','); t_column_list = tss.count; t_column_list_ptr = malloc(sizeof(t_column_list) * t_column_list); for(i=0;i<tss.count;i++){ t_column_list_ptr[i]=strtol(tss.str_array[i], NULL, 10); } str_split_free(&tss); //檢查參數(shù)ColumnList if (t_column_list>colTotal){ printf("[%s] 超過最大列數(shù) %d\n", ColumnList, colTotal); goto label_error; } for(i=0; i<t_column_list; i++){ if(t_column_list_ptr[i] > colTotal){ printf("[%s] 超過最大列數(shù) %d\n", ColumnList, colTotal); goto label_error; } } } //檢查是否超過,最大列數(shù) if(rowTotal <1 || colTotal <1 || skiprows>rowTotal){ printf("數(shù)據(jù)不對(duì),有%d行,%d列\(zhòng)n", rowTotal, colTotal); goto label_error; } //分配內(nèi)在空間 rowTotal = rowTotal - skiprows; temp_csv = (struct csv_s *)malloc(sizeof(struct csv_s) + (rowTotal * t_column_list)*sizeof(Dtype)); if(!temp_csv){ printf("分配內(nèi)存失敗 \n"); goto label_error; } // 讀取數(shù)據(jù) i = skiprows; fseek(fCsv, 0, SEEK_SET); //跳過開頭N行 while(i>0 && fgets(strLine,MAX_LINE_SIZE,fCsv) )i--; i = rowTotal; while( i>=0 && fgets(strLine,MAX_LINE_SIZE,fCsv)){ //printf("%d %s\n", i, strLine); i--; str_split_func(&tss, strLine, delimiter); if(t_column_list > tss.count){ printf("read error\n"); goto label_error; } int t_res = 0; for(j=0; j<t_column_list; j++){ t_res = strToData(temp_csv->data+cur_ptr, tss.str_array[t_column_list_ptr[j]], dclass); if(t_res < 0){ printf("str to data error\n"); goto label_error; } cur_ptr++; } str_split_free(&tss); } temp_csv->drow = rowTotal; temp_csv->dcol = t_column_list; temp_csv->dnum = rowTotal * t_column_list; //printf("%d %d %d\n", i, rowTotal, t_column_list); //for(i=0;i<temp_csv->dnum; i++) // printf("%d ", temp_csv->data[i].s32); //temp_csv->dtype = dtype; temp_csv->darray=NULL; setNewArray(temp_csv,temp_csv->drow, temp_csv->dcol); // 關(guān)閉文件 fclose(fCsv); free(t_column_list_ptr); return temp_csv; label_error: if(fCsv)fclose(fCsv); if(temp_csv)free(temp_csv); if(t_column_list_ptr)free(t_column_list_ptr); return NULL; } int testData() { int size=1000; //分配內(nèi)存空間 struct csv_s *stdata=(struct csv_s *)malloc(sizeof(struct csv_s) + size*sizeof(Dtype)); int i; //初始化數(shù)據(jù) for(i=900; i<size; i++){ // *((long int *)(stdata->data+i)) = i; *((double *)(stdata->data+i)) = i*1.0; } //隨機(jī)測(cè)試 初始化數(shù)據(jù) *((double *)(stdata->data+1)) = 10*1.0; printf("%f asdfasfasdf\n", *((double *)(stdata->data+1))); //初始化結(jié)構(gòu) int row = 500; int col = 2; stdata->drow= row; stdata->dcol = col; //stdata->dtype = sizeof(Dtype); stdata->dnum = row * col; int j=0; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray %d error\n", j); return 0; } //顯示結(jié)構(gòu)數(shù)據(jù) printf("顯示定義結(jié)構(gòu)最后一行數(shù)據(jù) \n"); for(j=0; j<col; j++){ printf("%f\n", stdata->darray[row-1][j].f64); } //結(jié)構(gòu)轉(zhuǎn)換 row = 100; col = 10; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray 轉(zhuǎn)換 %d error\n", j); return 0; } printf("顯示結(jié)構(gòu)轉(zhuǎn)換最后一行數(shù)據(jù) \n"); //顯示結(jié)構(gòu)數(shù)據(jù) for(j=0; j<col; j++){ printf("%f\n", stdata->darray[row-1][j].f64); } return 0; } //測(cè)試浮點(diǎn)數(shù) void testFile() { struct csv_s *stdata; //stdata = ReadCsvData("123.csv", ',', 1, "1,2", F32); stdata = ReadCsvData("123.csv", ',', 1, "2,1", F32); printf("testFile row %d col %d\n", stdata->drow, stdata->dcol); int i, j; //單獨(dú)以Dtype顯示數(shù)據(jù),是一個(gè)二維數(shù)組,以stdata->drow, stdata->dcol為行,列:Dtype show[stdata->drow][stdata->dcol] Dtype ** show = stdata->darray; printf("顯示最后一行數(shù)據(jù) \n"); for(j=0; j<stdata->dcol; j++){ printf("%f\n", show[stdata->drow-1][j].f32); } //結(jié)構(gòu)轉(zhuǎn)換 int row = 3; int col = 4; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray 轉(zhuǎn)換 %d error\n", j); }else{ //顯示結(jié)構(gòu)數(shù)據(jù) printf("顯示結(jié)構(gòu)轉(zhuǎn)換最后一行數(shù)據(jù) \n"); for(j=0; j<col; j++){ printf("%f\n", stdata->darray[row-1][j].f32); } } printf("轉(zhuǎn)換失敗測(cè)試\n"); //結(jié)構(gòu)轉(zhuǎn)換 row = 3; col = 2; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray 轉(zhuǎn)換 %d error\n", j); } //釋放內(nèi)存 FreeCsvData(&stdata); if(stdata==NULL) printf("ok t is null\n"); else printf("ok t is not null\n"); } //測(cè)試整數(shù)類型 void testFile2() { struct csv_s *stdata; //stdata = ReadCsvData("123.csv", ',', 1, "1,2", F32); stdata = ReadCsvData("123.csv", ',', 1, "2,1", DEF); printf("testFile row %d col %d\n", stdata->drow, stdata->dcol); int i, j; //單獨(dú)以Dtype顯示數(shù)據(jù),是一個(gè)二維數(shù)組,以stdata->drow, stdata->dcol為行,列:Dtype show[stdata->drow][stdata->dcol] //注意:這個(gè)默認(rèn)long int 數(shù)據(jù)類型 Dtype ** show = stdata->darray; printf("顯示最后一行數(shù)據(jù) \n"); for(j=0; j<stdata->dcol; j++){ printf("%d\n", show[stdata->drow-1][j]); } //結(jié)構(gòu)轉(zhuǎn)換 int row = 3; int col = 4; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray 轉(zhuǎn)換 %d error\n", j); }else{ //顯示結(jié)構(gòu)數(shù)據(jù) printf("顯示結(jié)構(gòu)轉(zhuǎn)換最后一行數(shù)據(jù) \n"); for(j=0; j<col; j++){ printf("%d\n", stdata->darray[row-1][j]); } } printf("轉(zhuǎn)換失敗測(cè)試\n"); //結(jié)構(gòu)轉(zhuǎn)換 row = 3; col = 2; j = setNewArray(stdata,row, col); if(j<0){ printf("setNewArray 轉(zhuǎn)換 %d error\n", j); } //釋放內(nèi)存 FreeCsvData(&stdata); if(stdata==NULL) printf("ok t is null\n"); else printf("ok t is not null\n"); } int main(int args, char *argv) { // testData(); testFile(); testFile2(); return 0; }
到此這篇關(guān)于C語言實(shí)現(xiàn)讀取CSV文件的方法詳解的文章就介紹到這了,更多相關(guān)C語言讀取CSV內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ 流插入和流提取運(yùn)算符的重載的實(shí)現(xiàn)
這篇文章主要介紹了C++ 流插入和流提取運(yùn)算符的重載的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12數(shù)據(jù)結(jié)構(gòu)之歸并排序的實(shí)例詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之歸并排序的實(shí)例詳解的相關(guān)資料,這里對(duì)歸并排序進(jìn)行詳細(xì)介紹,需要的朋友可以參考下2017-08-08C語言中實(shí)現(xiàn)KMP算法的實(shí)例講解
KMP算法即字符串匹配算法,C語言中KMP可以避免指針回溯從而達(dá)到高效,接下來就來總結(jié)一下C語言中實(shí)現(xiàn)KMP算法的實(shí)例講解2016-06-06C++基礎(chǔ)學(xué)習(xí)之利用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列
這篇文章主要給大家介紹了關(guān)于C++基礎(chǔ)學(xué)習(xí)之利用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05c++基礎(chǔ)語法:構(gòu)造函數(shù)初始化列表
構(gòu)造函數(shù)需要初始化的數(shù)據(jù)成員,不論是否顯示的出現(xiàn)在構(gòu)造函數(shù)的成員初始化列表中,都會(huì)在該處完成初始化,并且初始化的順序和其在聲明時(shí)的順序是一致的,與列表的先后順序無關(guān)2013-09-09C++使用Kruskal和Prim算法實(shí)現(xiàn)最小生成樹
這篇文章主要介紹了C++使用Kruskal和Prim算法實(shí)現(xiàn)最小生成樹,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01