标签:
最近项目中,经常需要读取Csv文件。基本步骤是:
(1)按行读取
(2)然后将一行数据按逗号,分割为字符串数组
(3)将各列字符串转换成相应类型的数据 ,如int double类型
写了一个简单的Csv文件读取类,方便使用,可以按列名或列索引读取数据。将字符串转换成数字变量使用的是stringstream类。
如下:
#ifndef CSV_READER_H_ #define CSV_READER_H_ #include <vector> #include <map> #include <fstream> #include <sstream> #include <string> #include <algorithm> using std::string; using std::vector; using std::map; using std::ifstream; using std::stringstream; class CsvReader { public: //不区分大小写 比较字符串 struct NoCaseCompareStr { bool operator()(const string & str1, const string & str2) { string upper_str1(str1); string upper_str2(str2); std::transform(upper_str1.begin(),upper_str1.end(),upper_str1.begin(),toupper); std::transform(upper_str2.begin(),upper_str2.end(),upper_str2.begin(),toupper); return upper_str1.compare(upper_str2) >= 0 ? false : true; } }; typedef map<string,int,NoCaseCompareStr> ColumnIndexMap; CsvReader(); virtual ~CsvReader(); //加载Csv文件 bool LoadFile(const string & fileName); //读取一行数据 bool Read(); void Close(); //得到列名字段的索引 int GetColumnIndex(const string & columnName); //按列名索引读取 template<typename T> bool GetValue(int columnIndex, T & val); template<typename T> T GetValue(int columnIndex); //按列名提取数据 template<typename T> bool GetValue(const string & columnName, T & val); template<typename T> T GetValue(const string & columnName); //分割字符串为字符数组 static void SplitString(const string & str, vector<string> & str_vec, char delimiter); private: ColumnIndexMap _columnIndex; //字段所对应列的索引 vector<string> _lineData;//Csv文件一行数据 ifstream _fi; bool _fileIsOpen; string _line; stringstream _ss; }; template<typename T> T CsvReader::GetValue( const string & columnName ) { int columnIndex = this->GetColumnIndex(columnName); return this->GetValue<T>(columnIndex); } template<typename T> bool CsvReader::GetValue( const string & columnName, T & val ) { int columnIndex = this->GetColumnIndex(columnName); return this->GetValue(columnIndex,val); } template<typename T> T CsvReader::GetValue( int columnIndex ) { T val; _ss.clear(); _ss.str(""); if (columnIndex < 0 || columnIndex >= (int)_lineData.size()) { return T(); } else { _ss.str(_lineData[columnIndex]); } _ss >> val; return val; } template<typename T> bool CsvReader::GetValue( int columnIndex, T & val ) { if (columnIndex < 0 || columnIndex >= (int)_lineData.size()) { return false; } _ss.str(""); _ss.clear(); _ss.str(_lineData[columnIndex]); _ss >> val; return true; } #endif
cpp文件:
#include "CsvReader.h" CsvReader::CsvReader() : _fileIsOpen(false) { } CsvReader::~CsvReader() { this->Close(); } bool CsvReader::LoadFile( const string & fileName ) { if (_fileIsOpen) //先关闭原来的文件 { this->Close(); } _fi.open(fileName); if (!_fi.is_open()) { return false; } _fileIsOpen = true; //读取第一行数据,得到CSV文件各列字段名称,并生成索引 if (!this->Read()) { return false; } int columnCount = _lineData.size(); for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { _columnIndex[_lineData[columnIndex]] = columnIndex; } return true; } void CsvReader::Close() { _fi.close(); _lineData.clear(); _columnIndex.clear(); _fileIsOpen = false; } bool CsvReader::Read() { while (_fileIsOpen && !_fi.eof()) { _line.clear(); std::getline(_fi,_line); if (_line.empty()) continue; _lineData.clear(); CsvReader::SplitString(_line,_lineData,‘,‘); if (_lineData.size() < _columnIndex.size()) { continue; } return true; } return false; } void CsvReader::SplitString( const string & str, vector<string> & str_vec, char delimiter ) { if (str.empty()) return; std::string::size_type pos = 0; std::string::size_type pre_pos = 0; while((pos = str.find_first_of(delimiter,pos)) != std::string::npos) { string tmp_str = str.substr(pre_pos,pos - pre_pos); str_vec.push_back(tmp_str); pre_pos = ++pos; } string tmp_str; if (pre_pos < str.size()) { tmp_str = string(&str[pre_pos]); } str_vec.push_back(tmp_str); } int CsvReader::GetColumnIndex( const string & columnName ) { ColumnIndexMap::const_iterator indexIt = _columnIndex.find(columnName); if (indexIt != _columnIndex.end()) { return indexIt->second; } return -1; }
标签:
原文地址:http://www.cnblogs.com/cmranger/p/4440430.html