- 精通Cocos2d-x游戲開發(進階卷)
- 王永寶
- 1236字
- 2020-11-28 22:36:57
1.4 讀取CSV文件
CSV格式是一種以逗號作為分隔符(也可以是其他符號,CSV格式并沒有一個通用的標準),存儲表格數據的文本格式,可以在Excel和WPS中方便地編輯CSV文件,使用Excel強大的功能,可以很好地管理CSV表格中的數據,例如,用公式來批量修改數值,對表格中的數據進行排序、篩選等。如圖1-1演示了在WPS中打開的一個CSV文件。

圖1-1 CSV表格
CSV由逗號作為分隔符來描述每一個字段,用換行符來描述每一列數據。因為CSV格式本身非常簡單,所以解析工作也非常簡單,接下來會把CSV的解析工作實現。
在開始寫代碼之前,先來見識CSV的廬山真面目,像圖1-1這樣的一個表格,用文本編輯器打開,看到的內容是下面這樣的,每一行數據占一行,數據之間用逗號分開。
用戶ID,用戶名,等級,陣營 1, kx,10,部落 2, wang,2,聯盟 3, abc,4,聯盟
這只是一個簡單的CSV文件,當字段中包含了逗號、雙引號或者換行符時,解析會變得麻煩,當一個字段中包含了逗號或換行符時,Excel會自動使用雙引號將整個字段包裹起來,而如果字段中包含了雙引號且整個字段被雙引號包裹,Excel則會自動將字段中的雙引號替換成兩個雙引號。具體的規則可以參考RFC4180規范http://tools.itef.org/html/rfc4180。
1.4.1 解析CSV
要解析前面的CSV文件,只需要進行簡單的字符串解析即可,因為CSV配置文件一般都放在Resource目錄下,所以需要用fullPathFromRelativePath將完整的路徑取出來,并且使用getFileData來讀文件。
//獲取路徑 string path = FileUtils::getInstance()->fullPathForFilename(fileName); //讀取文件 string csvFile = FileUtils::getInstance()->getStringFromFile(path);
現在得到了一個字符串csvFile,對這個字符串進行解析可以得到文件中每一個字段的內容,這里封裝了一個CSVLoader用于解析CSV文件格式,使用它來解析前面的CSV文件,然后將每個字段的內容打印出來。代碼如下:
CCsvLoader loader; if (loader.LoadCSV("test.csv")) { //跳過第一行,從第二行開始打印CSV文件內容 while (loader.NextLine()) { //順序取出CSV文件每一行的每個字段,并進行打印 int uid = loader.NextInt(); string name = loader.NextStr(); int lv = loader.NextInt(); string camp = loader.NextStr(); CCLOG("uid %d name %s lv %d camp %s", uid, name.c_str(), lv, camp. c_str()); } }
運行程序后打印的結果如下。
uid 1 name kx lv 10 camp red uid 2 name wang lv 2 camp blue uid 3 name abc lv 4 camp blue
如果直接在CCLOG語句中打印則有可能輸出其他的結果,因為函數參數入棧的順序是從右到左的,也就是最后的NextStr先執行。
CCLOG("uid %d name %s lv %d camp %s", loader.NextInt(), loader.NextStr().c_str(), loader.NextInt(), loader.NextStr().c_str());
1.4.2 描述復雜結構
在CSV中描述復雜的數據結構是比較麻煩的事情,例如,要在一個字段里面表示多個信息,那么可以用其他的分隔符來描述這個結構,如我們的位置字段包含了x和y兩個坐標的信息,那么可以用x|y或者x+y、x! y之類的寫法,用分隔符來區分一個字段中的多個信息,又如我們希望將一個不定長度的int數組存儲到CSV文件中。
可以用CSVLoader的SplitStrToVector()方法,傳入這個字段和設定的分隔符,來解析這串數據。當然可以用多個字段來描述,但這作為一種比較靈活的方法,可以在有限的字段里,表現更加復雜的結構,豐富的內容,對于要描述一些動態的屬性是比較有幫助的。
//傳入要解析的字符串str、分隔符sep以及用于接收分隔后的字符串容器out bool CCsvLoader::SplitStrToVector(const std::string &str, char sep, std:: vector<std::string>& out) { int pos = 0; int step = 0; while (static_cast<unsigned int>(pos) < str.length() && step ! = -1) { step = str.find_first_of(sep, pos); string seg = str.substr(pos, step); out.push_back(seg); pos = step + 1; } return out.size() > 0; }
通過調用SplitStrToVector()方法,可以先將字符串解析到vector中,然后再將vector中的字符串進行解析。通過使用不同的分隔符,還可以在CSV文件中描述多維數組。CSV文件的寫入一般不會用到,如果需要生成CSV文件,可以直接按照CSV的格式(逗號分隔加換行)寫入一個文本文件。