官术网_书友最值得收藏!

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的格式(逗號分隔加換行)寫入一個文本文件。

主站蜘蛛池模板: 于田县| 北流市| 剑阁县| 彭泽县| 金川县| 榕江县| 西峡县| 明溪县| 德安县| 洛浦县| 浙江省| 盱眙县| 温泉县| 抚州市| 固安县| 北流市| 东辽县| 临潭县| 咸宁市| 同江市| 黑水县| 广平县| 合山市| 广平县| 长垣县| 天水市| 烟台市| 江川县| 杨浦区| 大渡口区| 吉水县| 柳江县| 武功县| 大厂| 阿巴嘎旗| 什邡市| 海原县| 客服| 宿州市| 广丰县| 西畴县|