c++ 读取并解析excel文件方法
用Cocos开发模型特效工具编辑器,跨Mac和windows,当中有个需求是读取并解析excel文件,但网上的查找的例子几乎都只能是在windows下面使用,再或者是命令行脚本之类的。于是,自己写了一个非常轻量级的excel解析代码,纯cpp,除了依赖几个cocos2d 方法(zip解压和tinyxml2解析库),不依赖任何系统API。 目前只能解析常见的表式结构(如果把excel当成word文档使用就别看下面了),分享给大家,
如转发还请注明出处,感谢。
为了保证mac和windows都可以跑过,所以去掉注释,原谅我是VS菜鸟,当然代码够简单不写也能看懂。
getSheetArray返回的是excel的 行数组 ,因为c++里面难以实现动态类结构,所以不得已写成这种方式,一般情况下该数据拿到后需要二次加工,你可以拿一个简单的excel表格(比如道具物品表),测试打个断点就知道有哪些数据结构。 我还有一个纯js版本的,适合cocos2d-js使用,待日后完善了再丢出来。
// // Excel.h // 基于com.lipi.excel as3 版本设计,感谢lipi的源码参考 // Created by howe on 15/5/5. // auto excel = new Excel(); // bool result = excel->parseExcelFile(filepath, 1); // std::vector<LineInfo> arr = std::move( excel->getSheetArray() ); // #ifndef __ModelEditor__Excel__ #define __ModelEditor__Excel__ #include <stdio.h> #include <vector> #include <map> struct LineInfo { int lineIndex; std::vector<std::string> array; }; class Excel { public: Excel(); bool parseExcelFile(const std::string &filepath,int sheetIndex); std::vector<LineInfo> getSheetArray(); private: std::vector<std::string> _getValueArray(); private: std::map<int,LineInfo> excelHash; std::string _excelFilePath; }; #endif /* defined(__ModelEditor__Excel__) */
Excel.cpp 实现部分
// // Excel.cpp // // Created by howe on 15/5/5. // // #include <iostream> #include <string> #include "Excel.h" #include "cocos2d.h" #include "external/tinyxml2/tinyxml2.h" using namespace tinyxml2; using namespace std; unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t *size) { return cocos2d::FileUtils::getInstance()->getFileDataFromZip(zipFilePath, filename, size); } void deleteNum( std::string &content) { string::iterator t = content.begin(); while(t != content.end()) { if(*t >= '0' && *t <= '9') { content.erase(t); } else { t++; } } } int getColIndex(std::string &content) { auto returnValue = 0; for (auto i =0; i < content.length(); i++) { char n = content[i]; auto cValue = n - 64; returnValue *= 26; returnValue += cValue; } return returnValue - 1; } Excel::Excel() :_excelFilePath("") { } bool Excel::parseExcelFile(const std::string &ilepath, int sheetIndex) { _excelFilePath = ilepath; excelHash.clear(); char xml_file[256] = {0}; sprintf(xml_file, "xl/worksheets/sheet%d.xml",sheetIndex+1); ssize_t size; auto fileData = getFileDataFromZip(_excelFilePath, xml_file, &size); if (!fileData) { CCLOG(ilepath.c_str(), "The excel file is not exist!"); return false; } auto valueArray = std::move(_getValueArray()); tinyxml2::XMLDocument doc; doc.Parse((const char*)fileData,size); XMLElement *root = doc.RootElement(); XMLElement * sheetDataElement = root->FirstChildElement("sheetData"); XMLElement * rowElement =sheetDataElement->FirstChildElement("row"); while (rowElement) { LineInfo lineInfo; auto rowIndex = atoi(rowElement->Attribute("r")) - 1; lineInfo.lineIndex = rowIndex; std::vector<std::string> &rowArray = lineInfo.array; auto cElement = rowElement->FirstChildElement("c"); while (cElement) { std::string cc = cElement->Attribute("r"); deleteNum(cc); auto colIndex = getColIndex( cc ); std::string t = ""; std::string v = ""; if (cElement->Attribute("t")) { t = cElement->Attribute("t"); } auto vElement = cElement->FirstChildElement("v"); if (vElement) { v = vElement->GetText(); } if (rowArray.size() < colIndex) { int len = rowArray.size(); for (auto i = 0;i < colIndex - len;i++) { rowArray.push_back(""); // } } if (t == "s") { rowArray.push_back(valueArray[atoi(v.c_str())]); } else { rowArray.push_back(v); } cElement = cElement->NextSiblingElement("c"); } auto bb = false; for (auto iii : rowArray) { if (iii.length() > 1) { bb = true; break; } } if (bb) { excelHash[rowIndex] = lineInfo; } rowElement = rowElement->NextSiblingElement("row"); } return true; } std::vector<std::string> Excel::_getValueArray() { std::vector<std::string> result; ssize_t size; auto fileData = getFileDataFromZip(_excelFilePath, "xl/sharedStrings.xml", &size); tinyxml2::XMLDocument doc; doc.Parse((const char*)fileData,size); XMLElement *root = doc.RootElement(); XMLElement *siElement = root->FirstChildElement("si"); while (siElement) { std::string temp = ""; auto tElement = siElement->FirstChildElement("t"); while (tElement) { temp = temp + tElement->GetText(); tElement = tElement->NextSiblingElement("t"); } result.push_back(temp); siElement = siElement->NextSiblingElement("si"); } return result; } std::vector<LineInfo> Excel::getSheetArray() { std::vector<LineInfo> result; for ( auto ite = excelHash.begin();ite != excelHash.end();ite++) { auto &lineInfo_ = ite->second; result.push_back(lineInfo_); } return result; }