C++读取CSV表格

看到这个题目可能会有人问什么是CSV表格呢,在我做这个实现之前我也是没有听说过CSV表格,更不知道他有什么用了。CSV是一种Excel表格的导出格式,在Excel表格的菜单栏中点击文件->另存为会弹出一个文件夹浏览窗口,在下拉框中可以选择保存格式,其中有一个就是.CSV(逗号分隔符)选项。

CSV表格的规则:

1 开头是不留空,以行为单位。

2 可含或不含列名,含列名则居文件第一行。

3 一行数据不垮行,无空行。

4 以半角逗号(即,)作分隔符,列为空也要表达其存在。

5 列内容如存在半角逗号(即,)则用半角引号(即"")将该字段值包含起来。

6 列内容如存在半角引号(即")则应替换成半角双引号("")转义,并用半角引号(即"")将该字段值包含起来。

7 文件读写时引号,逗号操作规则互逆。

8 内码格式不限,可为 ASCII、Unicode 或者其他。

9 不支持特殊字符

CSV表格的用途:

CSV表格也相当于关系数据库中的二维表,但是他并不支持SQL语句的查询,只能通过一些手段将表格内容存入合适的数据结构中便于查询。如果结构选择的合适,那么查询起来还是很方便的,但是他不利于表格中数据的更新,更新就好比是文件的操作一样,各种文件指针游来游去,很繁琐。如果程序中要使用外部数据,数据又不多不值当去用数据库的话,就可以考虑使用CSV表格存储外部数据,每当程序执行时可以从外部读取数据进入内存,避免了程序因数据的改动而重新编译。


使用C++读取CSV表格的大致思路:

1:以打开文件的方式打开CSV表格,通过文件指针的各种游走,划分出每一行,将一行数据存到一个string对象中。循环读取文件中的每一行,文件读取完毕后悔生成一个map这样的对象,int表示行号,string表示这一行中的所有字符。使用到的函数是strchr

2:再对每一行进行分割,分割的标准就是逗号。这样对每一行来说会被分割出cols个string对象,把这些对象也存储在一个map对象中,这里的int表示从左到右的列号,从1数起。这样每一行数据会生成一个

map对象,处理完一个文本会生成一个map>对象。利用一个二重的映射关系将表格中的每一个字段全部有规律的存储起来。


下面是具体的实现代码:

#pragma once
//#include "stringparser.h"
#include 
#include 
#include 
#include 
#include "SkillRecord.h"
using namespace std;

typedef unsigned long   u32;

class CppCSV
{
private:
	map> m_stringMap;
	string m_CSVName;
public:
	CppCSV(){}
	CppCSV(const char *path)
	{
		assert(LoadCSV(path));
	}
	~CppCSV(){}

	bool LoadCSV(const char *path);
	bool SaveCSV(const char *path = NULL);

	bool GetIntValue(u32 uiRow, u32 uiCol, int &riValue);
	bool GetFloatValue(u32 uiRow, u32 uiCol, float &rfValue);
	string* GetStringValue(u32 uiRow, u32 uiCol);

	int GetParamFromString(string str, vector &stringVec, char delim  = ',');


	map>& GetCSVMap()
	{
		return m_stringMap;
	}

	void GetSkillRecordMapTable(map &sSkillMapTable);
};

#include "CppCSV.h"
#include 
//#include "stringparser.h"

bool CppCSV::LoadCSV(const char *path)
{
	FILE *pFile = fopen(path, "r");

	if (pFile)
	{
		fseek(pFile, 0, SEEK_END);
		u32 uSize = ftell(pFile);
		rewind(pFile);

		char *fileBuffer = new char[uSize];
		fread(fileBuffer, 1, uSize, pFile);

		map stringMap;
		u32 uiIndex = 1;
		char *pBegin = fileBuffer;
		char *pEnd = strchr(pBegin, '\n');


		pBegin = pEnd + 1;
		pEnd = strchr(pBegin, '\n');

		while (pEnd)
		{
			string strTemp;
			strTemp.insert(0, pBegin, pEnd-pBegin);
			assert(!strTemp.empty());
			stringMap[uiIndex++] = strTemp;
			pBegin = pEnd + 1;
			pEnd = strchr(pBegin, '\n');
		}
		delete []fileBuffer;
		fileBuffer = NULL;
		pBegin = NULL;
		pEnd = NULL;

		map::iterator iter = stringMap.begin();
		for (; iter != stringMap.end(); ++iter)
		{
			vector stringVec;
			map stringMapTemp;
			assert(GetParamFromString(iter->second, stringVec) > 0);
			
			vector::size_type idx = 0;
			for (; idx != stringVec.size(); ++idx)
			{
				stringMapTemp[idx + 1] = stringVec[idx];
			}

			m_stringMap[iter->first] = stringMapTemp;
		}

		fclose(pFile);
		m_CSVName = path;
		return true;
	} 
	else
	{
		return false;
	}
}

bool CppCSV::SaveCSV(const char *path /* = NULL */)
{
	if (path != NULL)
	{
		m_CSVName = path;
	}

	FILE *pFile = fopen(m_CSVName.c_str(), "w");
	if (pFile)
	{
		map>::iterator iter = m_stringMap.begin();
		for (; iter != m_stringMap.end(); ++iter)
		{
			map &rStringMap = iter->second;
			map::iterator it = rStringMap.begin();
			for (; it != rStringMap.end(); ++it)
			{
				string strTemp = it->second;
				strTemp += ',';
				fwrite(strTemp.c_str(), 1, 1, pFile);
			}

			char delim = '\n';
			fwrite(&delim, 1, 1, pFile);
		}

		fclose(pFile);
		return true;
	} 
	else
	{
		return false;
	}
}

bool CppCSV::GetIntValue(u32 uiRow, u32 uiCol, int &riValue)
{
	string *pStr = GetStringValue(uiRow, uiCol);
	if (pStr)
	{
		riValue = atoi(pStr->c_str());
		return true;
	} 
	else
	{
		return false;
	}
}

bool CppCSV::GetFloatValue(u32 uiRow, u32 uiCol, float &rfValue)
{
	string *pStr = GetStringValue(uiRow, uiCol);
	if (pStr)
	{
		rfValue = atof(pStr->c_str());
		return true;
	} 
	else
	{
		return false;
	}
}

string* CppCSV::GetStringValue(u32 uiRow, u32 uiCol)
{
	map>::iterator iter = m_stringMap.find(uiRow);
	if (iter != m_stringMap.end())
	{
		map &rStrMap = iter->second;
		map::iterator it = rStrMap.find(uiCol);
		if (it != rStrMap.end())
		{
			return &(it->second);
		} 
		else
		{
			return NULL;
		}
	} 
	else
	{
		return NULL;
	}
}

//用于分割字符串,将CSV表格中的一行按照规则解析成一组字符串,存储在一个vector中
//根据CSV表格中所存储的数据的不同,重载各函数
int CppCSV::GetParamFromString(string str, vector &stringVec, char delim)
{
	char *token = strtok(const_cast(str.c_str()), &delim);
	while (token)
	{
		string strTemp = token;
		stringVec.push_back(strTemp);
		token = strtok(NULL, &delim);
	}

	return stringVec.size();
}

void CppCSV::GetSkillRecordMapTable(map &sSkillMapTable)
{
	map>::iterator iter = m_stringMap.begin();
	for (; iter != m_stringMap.end(); ++iter)
	{
		map strmap = iter->second;
		SkillRecord skillTemp;
		skillTemp.SetID(atoi(strmap[1].c_str()));
		skillTemp.SetPath(strmap[2]);
		skillTemp.SetName(strmap[3]);
		skillTemp.SetHurt(atoi(strmap[4].c_str()));
		skillTemp.SetPlayTime(atoi(strmap[5].c_str()));

		sSkillMapTable[skillTemp.GetID()] = skillTemp;
	}
}
测试代码:

	CppCSV cs("skill.csv");
	map> stringMap = cs.GetCSVMap();

	map>::iterator iter = stringMap.begin();
	for (; iter != stringMap.end(); ++iter)
	{
		map strmap = iter->second;
		map::iterator it = strmap.begin();
		for (; it != strmap.end(); ++it)
		{
			cout<second<<"  ";
		}
		cout<


由于从文件中读取出来的内容都是存储在string对象中,如果文件呢存储的是一定意义的数据,需要进行转换了。

你可能感兴趣的:(C/C++)