CSV(Comma-Separated Values,逗号分隔的值)是一种简单、实用的文件格式,用于存储和表示包括文本、数值等各种类型的数据。CSV 文件通常以 .csv
作为文件扩展名。这种文件格式的一个显著特点是:文件内的数据以逗号( ,)或空格
分隔,呈现一个表格形式。CSV 文件已广泛应用于存储、传输和编辑数据。
CSV 文件基于纯文本格式,因此可以使用任何文本编辑器(如Notepad)轻松打开和编辑。它让程序开发人员喜欢的是既容易生成,还可以用其他编辑器编辑;作为数据输入时,也很好验证读取是否正确。本文介绍一个csv文件读取类,输入文件名就可以按行和列获取每个单元格的内容。
输入文件名,解析数据类:
#ifndef _CSV_FILE_
#define _CSV_FILE_
#include <fstream>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
typedef vector< string > VecString;
typedef vector< VecString > MatrixString;
class CVSFile
{
public:
CVSFile();
//以文件名初始化表格数据
bool Init(const char* szFileName, char cSpliteToken = ',');
//以指定分隔符从一行数据中获取关键字列表
bool Splite(const string& strLine, VecString& vecString);
private:
// 检测读出的数据是否合法
bool _CheckDataValid();
protected:
MatrixString m_content;
char m_cSpliteToken;
};
#endif
#include "CVSFile.h"
CVSFile::CVSFile()
{
m_content.clear();
}
bool CVSFile::Init( const char* szFileName, char cSpliteToken)
{
ifstream inFile(szFileName);
if (!inFile)
{
return false;
}
//获取分隔符
m_cSpliteToken = cSpliteToken;
// 每次读取一行文本内容直至文件结尾
string strLineContext;
while (getline(inFile, strLineContext))
{
// 以指定分隔符获取每行信息列表
VecString vecValue;
Splite(strLineContext, vecValue);
m_content.push_back(vecValue);
}
// 检验数据是否符合要求
if (!_CheckDataValid())
{
return false;
}
return true;
}
bool CVSFile::Splite( const string& strLine, VecString& vecString )
{
int nBegin = 0;
int nEnd = 0;
while ((nEnd = strLine.find_first_of(m_cSpliteToken, nBegin)) != string::npos)
{
vecString.push_back(strLine.substr(nBegin, nEnd - nBegin));
nBegin = nEnd + 1;
}
if ((nBegin = strLine.find_last_of(m_cSpliteToken, strLine.length() - 1)) != string::npos)
{
vecString.push_back(strLine.substr(nBegin + 1, strLine.length() - 1));
}
return true;
}
bool CVSFile::_CheckDataValid()
{
int nNumInOneLine = 0;
MatrixString::const_iterator itRowData = m_content.begin();
for (; itRowData != m_content.end(); itRowData++)
{
const VecString& curVecString = *itRowData;
nNumInOneLine = curVecString.size();
if (nNumInOneLine == 0)
{
return false;
}
}
return true;
}
如果是普通的矩阵式csv文件读取,上面的类里,自己添加一个接口函数,从MatrixString里获取单元格的值就可以了。
如果要读取的csv文件复杂一些,每个数据单独命名,有名称、数据类型和描述,如下:
name | n11 | n12 | n13 | n14 | n15 |
type | int | float | char | string | int |
description | |||||
value | v11 | v12 | v13 | v14 | v15 |
单单上面的解析是不够的,需要对上面解析的数据进行二次加工。
#ifndef _GAME_CSV_FILE_
#define _GAME_CSV_FILE_
#include <vector>
#include <string>
#include "CVSFile.h"
using namespace std;
enum KEY_TYPE
{
KEY_TYPE_NULL = -1, // 未知类型
KEY_TYPE_EMPTY, // 空类型
KEY_TYPE_CHAR, // 字符类型
KEY_TYPE_DWORD, // 整形类型
KEY_TYPE_FLOAT, // 浮点类型
KEY_TYPE_STRING, // 字符串类型
KEY_TYPE_MAX
};
// 字段类型名称表
static char* KeyTypeName[] = { "",
"char",
"dword",
"float",
"string"
};
//字段类型信息结构
struct KEY
{
string description; //字段说明
string name; //字段名称
KEY_TYPE eType; //字段类型
};
const unsigned int DESCRIPTION_ROW_INDEX = 0; //字段说明在csv表中的行号
const unsigned int NAME_ROW_INDEX = 1; //字段名称在csv表中的行号
const unsigned int KEY_TYPE_ROW_INDEX = 2; //字段类型在csv表中的行号
const unsigned int KEY_TYPE_ROW_NUM = KEY_TYPE_ROW_INDEX + 1; //字段类型在csv表中的行数
class GameCSVFile : public CVSFile
{
public:
GameCSVFile();
// 通过文件名,获得字段类型信息
bool Format(const char* szFileName);
private:
// 通过字符串获得字段类型
KEY_TYPE _GetKeyType(const string& strKeyType);
protected:
vector< KEY > m_vecKeyType; // 字段信息记录
};
#endif
#include "GameCSVFile.h"
GameCSVFile::GameCSVFile()
{
m_vecKeyType.clear();
}
bool GameCSVFile::Format( const char* szFileName )
{
if (!Init(szFileName))
{
return false;
}
// 字段定义行数不足,返回失败
if (m_content.size() < KEY_TYPE_ROW_INDEX + 1)
{
return false;
}
// 形成字段说明数组
for (unsigned int i = 0; i < m_content[DESCRIPTION_ROW_INDEX].size(); i++)
{
KEY curKey;
curKey.description = m_content[DESCRIPTION_ROW_INDEX][i];
curKey.name = m_content[NAME_ROW_INDEX][i];
curKey.eType = _GetKeyType(m_content[KEY_TYPE_ROW_INDEX][i]);
m_vecKeyType.push_back(curKey);
}
return true;
}
KEY_TYPE GameCSVFile::_GetKeyType( const string& strKeyType )
{
for (int i = 0; i < sizeof(KeyTypeName); i++)
{
if (strKeyType.compare(KeyTypeName[i]) == 0)
{
return static_cast<KEY_TYPE>(i);
}
}
return KEY_TYPE_NULL;
}
另外还需要数据获取接口管理,这里不再贴出所有代码,有需要下载一下。