逗号分隔值(Comma-SeparatedValues,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。
CSV文件格式的通用标准并不存在,但是在RFC 4180中有基础性的描述。使用的字符编码同样没有被指定,但是7-bitASCII是最基本的通用编码。
一般情况下,CSV文件格式规则如下:
1. 开头是不留空,以行为单位。
2. 可含或不含列名,含列名则居文件第一行。
3. 一行数据不跨行,无空行。
4. 以半角逗号(即,)作分隔符,列为空也要表达其存在。
5. 列内容如存在半角逗号(即,)则用半角双引号(即"")将该字段值包含起来。
6. 列内容如存在半角引号(即")则应替换成半角双引号("")转义,并用半角引号(即"")将该字段值包含起来。
7. 文件读写时引号,逗号操作规则互逆。
8. 内码格式不限,可为 ASCII、Unicode 或者其他。
9. 不支持特殊字符
博文“C++读写CSV文件”提出了一种CSV文件的读取遍历算法和写入算法,http://www.cnblogs.com/snake-hand/p/3170483.html,并利用C++实现了对CSV文件的读、写操作。
本文结合OpenCV的CSV风格格式化输出与流缓冲重定向,比较巧妙地实现了“将Mat 矩阵数据存储到CSV文件”功能。
代码如下:
//保存cout流缓冲区指针 streambuf *coutBuf = cout.rdbuf(); fstream matData("E:\\Test\\data\\fire_2.csv",ios::out|ios::trunc); if(!matData){ cerr<<"File open or create error!"<<endl; exit(1); } //获取文件fire.csv的流缓冲区指针 streambuf *fileBuf = matData.rdbuf(); //设置cout流缓冲区指针为文件的流缓冲区指针 cout.rdbuf(fileBuf); cout<<format(svmMat,"csv"); matData.flush(); matData.close(); //恢复cout原来的流缓冲区指针 cout.rdbuf(coutBuf);
测试结果:
以下代码为我自己写的read_csv函数,实现了从CSV文件读取数据到Mat矩阵中的功能。
/** *函数功能:将csv文件数据提取到Mat类型矩阵中 *输入:filepath 文件路径数组指针;img_size Mat类型数据的Size;img_type Mat类型数据的类型(32FC1) *返回值:Mat 矩阵 */ Mat read_csv(const char *filepath, Size img_size, int img_type) { Mat image; image.create(img_size,img_type); string pixel; ifstream file(filepath, ifstream::in); if (!file) cout << "CSV read fail" << endl; int nl= image.rows; // number of lines int nc= image.cols ; // number of columns int eolElem = image.cols - 1; //每行最后一个元素的下标 int elemCount = 0; if (image.isContinuous()) { nc= nc*nl; // then no padded pixels nl= 1; // it is now a 1D array } for (int i = 0; i<nl; i++) { float* data = (float*)image.ptr<ushort>(i); for (int j = 0; j < nc; j++) { if(elemCount == eolElem){ getline(file,pixel,'\n'); //任意地读入,直到读到delim字符 '\n',delim字符不会被放入buffer中 data[j] = (float)atof(pixel.c_str()); //将字符串str转换成一个双精度数值并返回结果 elemCount = 0; //计数器置零 } else{ getline(file,pixel,','); //任意地读入,直到读到delim字符 ','delim字符不会被放入buffer中 data[j] = (float)atof(pixel.c_str()); //将字符串str转换成一个双精度数值并返回结果 elemCount++; } } } return image; }测试结果:
注意事项:
注意每一个记录结束时以’\n’结尾,而非’,’因此需要特别处理。
OpenCV 的实现:
在我调用read_csv函数时,发现OpenCV已经有实现类似功能的函数:intCvMLData::read_csv(const char* filename)。利用CMake编译OpenCV,点击鼠标右键->转到定义可以方便查看opencv的源代码。(具体方法见以下链接博文)http://blog.csdn.net/solomon1558/article/details/43780533
实现一:
例程Fisherfaces in OpenCV中的read_csv函数
static void read_csv(const string& filename, vector<Mat>&images, vector<int>& labels, char separator = ';'){ std::ifstream file(filename.c_str(),ifstream::in); if (!file){ string error_message = "No valid input file was given, please check thegiven filename."; CV_Error(CV_StsBadArg, error_message); } string line, path, classlabel; while(getline(file, line)) { stringstream liness(line); getline(liness, path, separator); getline(liness, classlabel); if(!path.empty()&& !classlabel.empty()) { images.push_back(imread(path, 0)); labels.push_back(atoi(classlabel.c_str())); } } }
实现二:int CvMLData::read_csv(const char* filename)
int CvMLData::read_csv(constchar* filename) { const int M = 1000000; const char str_delimiter[3] = { '', delimiter, '\0' }; FILE* file = 0; CvMemStorage* storage; CvSeq* seq; char *ptr; float*el_ptr; CvSeqReader reader; intcols_count = 0; uchar *var_types_ptr = 0; clear(); file = fopen( filename, "rt" ); if( !file ) return-1; // read the firstline and determine the number of variables std::vector<char>_buf(M); char* buf =&_buf[0]; if(!fgets_chomp( buf, M, file )) { fclose(file); return-1; } ptr = buf; while( *ptr== ' ' ) ptr++; for( ; *ptr!= '\0'; ) { if(*ptr== delimiter || *ptr == ' ') { cols_count++; ptr++; while(*ptr == ' ' ) ptr++; } else ptr++; } cols_count++; if (cols_count == 0) { fclose(file); return-1; } // createtemporary memory storage to store the whole database el_ptr = newfloat[cols_count]; storage = cvCreateMemStorage(); seq = cvCreateSeq( 0, sizeof(*seq), cols_count*sizeof(float), storage ); var_types = cvCreateMat( 1, cols_count,CV_8U ); cvZero( var_types ); var_types_ptr = var_types->data.ptr; for(;;) { char*token = NULL; inttype; token = strtok(buf, str_delimiter); if(!token) break; for (int i = 0; i < cols_count-1; i++) { str_to_flt_elem( token, el_ptr[i],type); var_types_ptr[i] |= type; token = strtok(NULL,str_delimiter); if(!token) { fclose(file); delete[] el_ptr; return-1; } } str_to_flt_elem( token,el_ptr[cols_count-1], type); var_types_ptr[cols_count-1] |= type; cvSeqPush( seq, el_ptr ); if(!fgets_chomp( buf, M, file ) ) break; } fclose(file); values = cvCreateMat( seq->total,cols_count, CV_32FC1 ); missing = cvCreateMat( seq->total,cols_count, CV_8U ); var_idx_mask = cvCreateMat( 1,values->cols, CV_8UC1 ); cvSet( var_idx_mask, cvRealScalar(1) ); train_sample_count = seq->total; cvStartReadSeq( seq, &reader ); for(int i = 0; i < seq->total; i++ ) { const float* sdata = (float*)reader.ptr; float*ddata = values->data.fl + cols_count*i; uchar* dm = missing->data.ptr +cols_count*i; for( int j = 0; j < cols_count; j++ ) { ddata[j] = sdata[j]; dm[j] = ( fabs( MISS_VAL - sdata[j]) <= FLT_EPSILON ); } CV_NEXT_SEQ_ELEM( seq->elem_size,reader ); } if (cvNorm( missing, 0, CV_L1 ) <= FLT_EPSILON ) cvReleaseMat( &missing ); cvReleaseMemStorage( &storage ); delete[]el_ptr; return 0; }
原文地址:http://blog.csdn.net/solomon1558/article/details/44730625