代码设计:C++ 一个CSV功能类(源码)

编程入门 行业动态 更新时间:2024-10-26 00:27:10

代码设计:C++ 一个CSV功能类(<a href=https://www.elefans.com/category/jswz/34/1770099.html style=源码)"/>

代码设计:C++ 一个CSV功能类(源码)

        CSV格式是逗号分隔的文本文件,几十年前挺常用,现在几乎没人用,但是因为很多工具都支持,可以作为各种数据迁移的中介,所以始终没有退出历史舞台。

        CSV格式非常简单,就是一行一条记录、逗号分隔字段而已。

        下面是个代码,主要是为了用excel编辑数据而做的,不保证和非execl的兼容性。

        主要的细节是对不同语言编码的处理和文本转换。因为用的只是UTF-8,所以只检测了UTF-8的BOM。

//csv格式文件处理#include <sys/stat.h>//基本csv功能class CCSV{private:CStdOSFile m_file;vector<string > m_Heads;//头标,如果no_head则没有头标public://根据路径名创建所有目录,不包括最后的文件名static bool CreateDir(char const* filename){string dirname;char const* p = filename;for (; '\0' != *p; ++p){dirname += *p;if ('/' == *p){//thelog<<dirname<<endi;mkdir(dirname.c_str(), S_IRWXU | S_IRWXG);}}return true;}//csv格式,双引号内为普通文本,文本内双引号要用两个双引号表达,简单起见全部加上了双引号static string& CSVEncode(char const* in, string& out){out = "";out += '\"';for (char const* p = in; *p != '\0'; ++p){if ('\"' == *p)out += '\"';out += *p;}out += '\"';return out;}//csv格式,双引号内为普通文本,文本内双引号要用两个双引号表达,简单起见全部加上了双引号static string CSVEncode(string const& in){string out;return CSVEncode(in.c_str(), out);}//打开文件bool OpenCSV(char const* filepatnname, bool no_head = false){m_Heads.clear();if (!CreateDir(filepatnname))return false;if (!m_file.OpenR(filepatnname))return false;if (!no_head){bool isLineEnd;string str;while (_ReadField(isLineEnd, str)){if (isLineEnd){break;}if (0 == m_Heads.size()){//对第一个消除可能存在的UTF-8签名(EF BB BF)if (0 == strncmp("\xEF\xBB\xBF", str.c_str(), 3)){str.erase(0, 3);}}//thelog << str << endi;m_Heads.push_back(str);}thelog << "获得列头 " << m_Heads.size() << " 个" << endi;}return true;}//获得字段序号long GetFieldIndex(char const* field)const{vector<string >::const_iterator it;for (it = m_Heads.begin(); it != m_Heads.end(); ++it){if (*it == field)return it - m_Heads.begin();}return -1;}//获得字段数long GetFieldCount()const{return m_Heads.size();}//获得字段名string GetFieldName(long field)const{return m_Heads[field];}//读取字段,或者是一个字段,或者是行结束bool _ReadField(bool& isLineEnd, string& ret){bool tmp = __ReadField(isLineEnd, ret);TrimAll(ret);return tmp;}bool __ReadField(bool& isLineEnd, string& ret){isLineEnd = false;ret = "";char m_c;string str;bool isFirstChar = true;bool isInStr = false;bool isInStrQuote = false;//是否在字符串内出现了一个双引号,这意味着字符串结束,或者一个内嵌双引号的开始while (1 == m_file.Read(&m_c, 1)){if (isFirstChar && ('\r' == m_c || '\n' == m_c)){//仅当第一个字符就是行结束才认为是行结束而没有获得数据isLineEnd = true;if ('\r' == m_c){if (1 == m_file.Read(&m_c, 1)){if ('\n' != m_c){m_file.SeekCur(-1);//不是连续\r\n,吐回去}}}return true;}else{isFirstChar = false;}if (isInStr && isInStrQuote && '\"' == m_c){//内嵌双引号ret = +m_c;isInStrQuote = false;continue;}if (isInStr && isInStrQuote && ',' == m_c){//字符串结束,逗号标记字段结束return true;}if (isInStr && isInStrQuote && ('\r' == m_c || '\n' == m_c)){//字符串结束,行结束m_file.SeekCur(-1);//吐回行结束,否则永远不能发现单独的行结束return true;}if (isInStr && isInStrQuote){//字符串结束isInStr = false;continue;}if (isInStr && !isInStrQuote && '\"' == m_c){//遇到内部第一个双引号isInStrQuote = true;continue;}if (isInStr && !isInStrQuote){//字符串内容,除了双引号都不用特殊判断ret += m_c;continue;}if (!isInStr && '\"' == m_c){//字符串开始isInStr = true;continue;}if (!isInStr && ',' == m_c){//字段结束return true;}if (!isInStr && ('\r' == m_c || '\n' == m_c)){//行结束m_file.SeekCur(-1);//吐回行结束,否则永远不能发现单独的行结束return true;}if (!isInStr){//非字符串的其余ret += m_c;continue;}}return false;}bool ReadField(string& ret){bool isLineEnd;while (_ReadField(isLineEnd, ret)){if (!isLineEnd)return true;}return false;}//关闭文件bool CloseCSV(){return m_file.Close();}//文件到表格bool LoadFromFile(char const* file, CHtmlDoc::CHtmlTable2 & table){table.Clear();CCSV csv;if (!csv.OpenCSV(file)){return false;}long i;for (i = 0; i < csv.GetFieldCount(); ++i){table.AddCol(csv.GetFieldName(i));}bool isLineEnd;string str;bool need_new_line = false;table.AddLine();while (csv._ReadField(isLineEnd, str)){if (isLineEnd){need_new_line = true;}else{if (need_new_line){table.AddLine();need_new_line = false;}table.AddData(str);}}table.Fill();return csv.CloseCSV();}};class CText{public://删除两端的空白,连续回车换行缩减为一个换行static string FormatText(char const* text){string ret = text;TrimAll(ret);string::size_type pos = 0;bool isInNewLine = false;while (pos < ret.size()){if ('\r' == ret[pos] || '\n' == ret[pos]){if (!isInNewLine){isInNewLine = true;ret[pos] = '\n';++pos;}else{//丢弃连续的换行,pos不变ret.erase(pos, 1);}}else{isInNewLine = false;++pos;}}return ret;}};

        这段代码中用到一些别的东西,基本上属于看到名字就能猜到功能的:

CStdOSFile 就是一个文件类,可以用任何别的文件类替换掉

CHtmlDoc::CHtmlTable2 这是一个表格类,可以输出为文本表格、HTML表格、变更JS,以后我可能会把这个类整理出来

TrimAll 删除两端空白字符

        这个代码是在UNIX、Linux上运行的。

        看注释应该能理解这个代码了,有问题也可以来问我。

(这里是结束)

更多推荐

代码设计:C++ 一个CSV功能类(源码)

本文发布于:2023-12-08 10:46:21,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1672625.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:源码   代码   功能   CSV

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!