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

来源:互联网 发布:地板革淘宝网 编辑:程序博客网 时间:2024/06/06 00:20

读取配置文件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;#elsem_pContext = buffer;#endifm_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;}//数据类型转换//转化为 charinline 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 charinline 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';}}}//转化为 shortinline void convert(short& target,const std::string& str){if (str.empty()){target = (short)0;}else{target = (short)atoi(str.c_str());}}//转化为unsigned shortinline void convert(unsigned short& target,const std::string& str){if (str.empty()){target = (unsigned short)0;}else{target = (unsigned short)atoi(str.c_str());}}//转化为 intinline void convert(int& target,const std::string& str){if (str.empty()){target = (int)0;}else{target = atoi(str.c_str());}}//转化为 intinline 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 longinline 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 doubleinline 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 longinline void convert(long long& target,const std::string& str){if (str.empty()){target = (long long)0;}else{target = (long long)atoll(str.c_str());}}//转化为 floatinline 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;}}}//转化为 doubleinline 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());#elsestrncpy((char *)target,str.c_str(),targetLen);#endifif (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编码#elsestrncpy(target,str.c_str(),targetLen);if (targetLen <= str.length())target[targetLen - 1] = 0;#endif}//转化为 std::stringinline 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());#elsetarget = str;#endif}//转化为 long longvoid 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'://去掉\rcase '\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);#endifif (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());}#elseif (*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_


0 0