读取配置文件csv的接口封装类

读取配置文件csv的接口封装类。

csv配置文件既可以在excel中方便编辑,又体积较小,分析速度较快,所以是作为游戏等软件配置文件的较好的选择。

由于csv配置文件没有较好的c++库的支持(目前没见到),可以根据自己的需求编写读取接口库。

使用规则是第一行是各个字段的字段标注,后面的各行是具体的数值。

由于csv比较方便是在windows的excel下编辑,一般是gbk编码的。而服务器程序一般是utf8编码的。根据需求,可以对中文字符串类型的变量进行转码。

代码如下:

#ifndef _CSVFILE_H_
#define	_CSVFILE_H_
#include <fstream>  
#include <string>  
#include <sstream>  
#include <vector>  
#include <stdlib.h>
#include <iostream>
#include <assert.h>
#include <algorithm>
#include "CodeConvert.h"
#include "assert/mAssert.h"

//该类为读取csv文件接口
//根据字段名称来找到所对应的值
class CSVFile  
{  
public:  
	CSVFile()
	{
		m_pContext = NULL;//文件内容指针
		m_pFile = NULL;//文件指针
		m_pLinePtr = NULL;//行头指针
	}
	~CSVFile()
	{
		if (NULL != m_pContext)
		{
			delete []m_pContext;
			m_pContext = NULL;
		}
		m_pLinePtr = NULL;
		m_pFile = NULL;
	}
<span style="white-space:pre">	</span>//读取文件内容到缓存
	inline bool Open(bool bIsRead, const char* strPath, const char* strFilename)
	{
		m_nFileState = FILE_STATE_NULL;
		m_sFullFileName = strPath;
		m_sFullFileName += strFilename;

		m_pFile = fopen(m_sFullFileName.c_str(), "rb");
		if(!m_pFile)
		{
			return false;
		}
		fseek(m_pFile, 0, SEEK_END);
		long size = ftell(m_pFile);
		fseek(m_pFile, 0, SEEK_SET);
		char *buffer = new char[size + 1];
		size_t nRead = fread(buffer, 1, size, m_pFile);
		fclose(m_pFile);
		if((long)nRead != size)
			return false;
		buffer[nRead] = 0;
<span style="white-space:pre">	</span>//如果程序编码是 utf8且 cvs配置文件编码是gbk则需要转码为utf8
	#if (UTF8 == PROGRAM_CODE) &&  (GBK == CSV_CODE)
		m_pContext = new char[size*2 + 1];
		int nConvertedSize = gbk2utf8(m_pContext,size*2,buffer);
		m_pContext[nConvertedSize] = '\0';
		delete []buffer;
	#else
		m_pContext = buffer;
	#endif
		m_pLinePtr = m_pContext;
		ReadCSVHead();//读取csv配置文件的第一行(也是配置的各个字段名称)
		if (bIsRead)
		{
			m_nFileState = FILE_STATE_READ;//开始读取文件数据
		}
		return true;
	}
	// 读取csv文件中的一行数据
	inline bool CSVReadNextRow()
	{
		if (m_nFileState != FILE_STATE_READ)
			return false;
		const char* sLine = m_pLinePtr;				//行头
		const char* sLineEnd = strchr(sLine, '\n');		//行尾

		if (!sLineEnd)
		{
			return false;
		}

		m_pLinePtr = sLineEnd + 1;
		if (sLineEnd[-1] == '\r')//去掉windows 文件的换行符的'\r'
			sLineEnd--;

		//一行内容空
		if(0 == (sLineEnd - sLine))
			return false;

		RowParse(sLine, int(sLineEnd - sLine), m_CSVCurRow);//读取该行数据
		return true;
	}
	template<class T>
	bool CSVRead(const char* strFieldName, T& target)//根据字段名称,读取该行与之相对应的值
	{
		std::string data;
		if (m_nFileState != FILE_STATE_READ)
		{
			return false;
		}

		int n = FindField(strFieldName);//获取该字段名称所在列数
		if (n == -1 || n >= (int)m_CSVCurRow.size())
		{
			return false;
		}

		data = m_CSVCurRow[n];//根据字段名称所在列数,找到该值
		convert(target,data);
		return true;  
	}  
	inline bool CSVRead(const char* strFieldName, char* target,size_t len)//根据字段名称,读取该行中之相对应的值
	{
		std::string data;
		if (m_nFileState != FILE_STATE_READ)
		{
			return false;
		}

		int n = FindField(strFieldName);//获取该字段名称所在列数
		if (n == -1 || n >= (int)m_CSVCurRow.size())
		{
			return false;
		}
		data = m_CSVCurRow[n];//根据字段名称所在列数,找到该值
		convert(target,len,data);
		return true;
	}

	template<class T>
	bool CSVWrite(const char* strFieldName, T data)//写接口,目前没有使用
	{
		if (m_nFileState != FILE_STATE_WRITE)
		{
			return false;
		}
		int n   = FindField(strFieldName);//找到字段名称所在的列数
		if (n == -1)
		{
			return false;
		}

		std::stringstream ss;
		ss << data;
		m_CSVCurRow[n]  = ss.str();
		return true;
	}
	//获取总行数
	inline size_t GetTotalRow()
	{
		const char* sLine = m_pContext;
		const char* sLineEnd = strchr(sLine, '\n');
		size_t nCount = 0;
		while (sLineEnd)
		{
			sLineEnd = strchr(sLineEnd, '\n');
			if(sLineEnd)
			{
				nCount++;
				sLineEnd++;
			}
			else
			    break;
		}
		return nCount-1;
	}
	//数据类型转换
	//转化为 char
	inline void convert(char& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (char)0;
		}
		else
		{
			target = str.c_str()[0];
			if (target>='0' && target <='9')
			{
				target = target - '0';
			}
		}
	}
	//转化为unsigned char
	inline void convert(unsigned char& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (unsigned char)0;
		}
		else
		{
			target = (unsigned char)str.c_str()[0];
			if (target>='0' && target <='9')
			{
				target = target - '0';
			}
		}
	}
	//转化为 short
	inline void convert(short& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (short)0;
		}
		else
		{
			target = (short)atoi(str.c_str());
		}
	}
	//转化为unsigned short
	inline void convert(unsigned short& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (unsigned short)0;
		}
		else
		{
			target = (unsigned short)atoi(str.c_str());
		}
	}

	//转化为 int
	inline void convert(int& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (int)0;
		}
		else
		{
			target = atoi(str.c_str());
		}
	}
	//转化为 int
	inline void convert(unsigned int& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (unsigned int)0;
		}
		else
		{
			target = (unsigned int)atol(str.c_str());
		}
	}

	//转化为 long(要64位的话,建议不使用long 而用long long,long在64位win下是4字节,在64位linux下是8字节)
	inline void convert(long& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (long)0;
		}
		else
		{
			target = (long)atol(str.c_str());
		}
	}
	//转化为 unsigned long
	inline void convert(unsigned long& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (unsigned long)0;
		}
		else
		{
			target = (unsigned long)strtoul(str.c_str(),NULL,0);
                         //char *endptr = NULL;
		}
	}

	//转化为 long double
	inline void convert(long double& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (long double)0;
		}
		else
		{
			target = (long double)atoll(str.c_str());
		}
	}

	//转化为 long long
	inline void convert(long long& target,const std::string& str)
	{
		if (str.empty())
		{
			target = (long long)0;
		}
		else
		{
			target = (long long)atoll(str.c_str());
		}
	}

	//转化为 float
	inline void convert(float& target,const std::string& str)
	{
		if (str.empty())
		{
			target = 0;
		}
		else
		{
			char *endptr = NULL;
			target = (float)strtod(str.c_str(),&endptr);
			if (endptr && endptr[0])
			{
				target = 0;
				std::cout <<  "config data error:" <<endptr << std::endl;
			}
		}
	}
	//转化为 double
	inline void convert(double& target,const std::string& str)
	{
		if (str.empty())
		{
			target = 0;
		}
		else
		{
			char *endptr = NULL;
			target = strtod(str.c_str(),&endptr);
			if (endptr && endptr[0])
			{
				target = 0;
				std::cout <<  "config data error:" <<endptr << std::endl;
			}
		}
	}

	//转化为 const char *
	inline void convert(const char *target,size_t targetLen,const std::string& str)
	{
		if (str.empty())
		{
		        bzero((char *)target,targetLen);
			return;
		}
	#if (UTF8 == PROGRAM_CODE) && (GBK == CSV_CODE)
		gbk2utf8(target,targetLen,str.c_str());
	#else
		strncpy((char *)target,str.c_str(),targetLen);
	#endif
		if (targetLen <= str.length())//最后字节置0
			*(char *)(target + targetLen - 1) = 0;
	}

	//转化为 char *
	inline void convert(char *target,size_t targetLen,const std::string& str)
	{
		if (str.empty())
		{
			bzero(target,targetLen);
			return;
		}
	#if (UTF8 == PROGRAM_CODE) &&  (GBK == CSV_CODE)
		gbk2utf8(target,(int)targetLen,str.c_str());//转换gbk编码到utf8编码
	#else
		strncpy(target,str.c_str(),targetLen);
		if (targetLen <= str.length())
			target[targetLen - 1] = 0;
	#endif
	}

	//转化为 std::string
	inline void convert(std::string& target,const std::string& str)
	{
		if (str.empty())
		{
			target.clear();
			return;
		}
#if (UTF8 == PROGRAM_CODE) &&  (GBK == CSV_CODE)
		gbk2utf8(target,str.c_str());
#else
		target = str;
#endif
	}
	//转化为 long long
	void convert(long long& target,const std::string& str)
	{
		if (str.empty())
		{
			target = 0;
		}
		else
		{
			char *endptr = NULL;
			target = (long long)strtod(str.c_str(),&endptr);
			if (endptr && endptr[0])
			{
				target = 0;
				std::cout <<  "config data error:" <<endptr << std::endl;
			}
		}
	}
private:  
	//保存每一行内容的容器
	typedef std::vector<std::string> ROWVEC;

	//读取字段名词行并保存起来
	inline void ReadCSVHead()
	{
		const char* sLine = m_pLinePtr;				//行头
		const char* sLineEnd = strchr(sLine, '\n');		//行尾
		if (sLineEnd)
		{
			m_pLinePtr = sLineEnd + 1;
			if (sLineEnd[-1] == '\r')
				sLineEnd--;
		}
		else sLine = sLineEnd = "";
		RowParse(sLine, int(sLineEnd - sLine), m_CSVHead);
	}
	//strRow是csv文件中的一行的起始位置
	//nSize 一行的长度
	//result 一行的各个字段的字符串队列
	inline void RowParse(const char* strRow, int nSize, ROWVEC& result)
	{
		result.clear();
		std::string strCurWord;
		for (int i = 0; i < nSize; ++i)
		{
			char ch = strRow[i];
			bool bIsAdd = true;
			switch (ch)
			{
			case ',':
				{
					//一项结束
					result.push_back(strCurWord);
					strCurWord = "";
					bIsAdd = false;
				}
				break;
			case '"':
			//去掉空格
	 		case ' ':
			case '\r'://去掉\r
			case '\t'://去掉\t
				{
					bIsAdd = false;
				}
				break;
			default:
				break;
			};

			if (bIsAdd)//添加合法字符
				strCurWord += ch;
		}
		result.push_back(strCurWord);
	}
	//删除字符串中的‘\r’字符
	inline void delete_r(std::string &str)
	{
		while(1)
		{
			std::string::iterator it = std::find(str.begin(), str.end(), '\r');
			if(it == str.end())
				break;
			str.erase(it);
		}
	}
	//strRow 是程序中的字段
	//return 字段列数
	inline int FindField(const char* strRow)//获取字段名称对应的列数
	{
	#if (UTF8 == PROGRAM_CODE) &&  (GBK == CSV_CODE)
		std::string tarStr;
		gbk2utf8(tarStr,strRow);
	#endif
		if (m_nFileState == FILE_STATE_NULL)
			return -1;
		for (ROWVEC::iterator it = m_CSVHead.begin();it != m_CSVHead.end(); it++)
		{
	#if (UTF8 == PROGRAM_CODE) &&  (GBK == CSV_CODE)
			if (*it == tarStr)
			{
				return int(it - m_CSVHead.begin());
			}
	#else
			if (*it == strRow)
			{
				return int(it - m_CSVHead.begin());
			}
	#endif
		}
		printf("字段 ( %s) 没有找到,配置文件为(%s)\n",strRow,m_sFullFileName.c_str());
		assert_fail("配置文件字段没有找到");
		return 0;
	}

	enum  FileState
	{
		FILE_STATE_NULL,  //未初始化
		FILE_STATE_READ,  //文件可写
		FILE_STATE_WRITE, //文件可读
	};  
	FileState    m_nFileState;//文件状态机
	//std::fstream    m_CSVFile;  
	FILE* m_pFile;
	char* m_pContext;
	const char* m_pLinePtr;			//行记录指针
	ROWVEC  m_CSVHead;  			//字段名称行
	ROWVEC  m_CSVCurRow;  			//当前内容行
	std::string m_sFullFileName;//文件名称全路径
};  


#endif	//_CSVFILE_H_


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值