标签:
最近项目中,经常需要读取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