C++CSVテーブルの読み込み
6963 ワード
このテーマを見るとCSV表とは何かと聞かれるかもしれませんが、私がこの実現をする前にCSV表を聞いたことがありません.彼が何の役に立つのか分かりません.CSVはExcelテーブルのエクスポート形式で、Excelテーブルのメニューバーでファイルをクリック->名前を付けて保存するとフォルダブラウズウィンドウがポップアップし、ドロップダウンボックスで保存形式を選択できます.CSV(カンマ区切り)オプション.
CSVテーブルのルール:
1先頭は、空白を残さずに動作単位で行います.
2カラム名を含むか含まないか、カラム名を含むとファイルの最初の行になります.
3 1行のデータは崩れず、空行はない.
4は半角カンマ(すなわち、)で区切り、列が空であってもその存在を表す.
5列の内容は、半角カンマ(すなわち、)がある場合は、半角引用符(すなわち「」)でフィールド値を含めます.
6列の内容に半角引用符(すなわち「)がある場合は、半角二重引用符(」")に置き換え、半角引用符(すなわち「」)でフィールド値を含めます.
7ファイルの読み書き時の引用符、カンマの操作規則は互いに逆です.
8イントラコードフォーマットは、ASCII、Unicodeまたはその他であってもよい.
9特殊文字はサポートされていません
CSV表の用途:
CSVテーブルもリレーショナル・データベースの2 Dテーブルに相当しますが、SQL文のクエリーはサポートされておらず、いくつかの手段でテーブルの内容を適切なデータ構造に格納するだけでクエリーが容易になります.構造選択が適切であれば、クエリーは便利ですが、表のデータの更新には不利で、更新はファイルの操作のように、さまざまなファイルポインタが泳いでいて、煩雑です.もしプログラムの中で外部のデータを使うならば、データはまた多くなくてデータベースを使うならば、CSV表を使って外部のデータを保存することを考慮することができて、プログラムが実行するたびに外部からデータを読み取ってメモリに入ることができて、プログラムがデータの変更によって再コンパイルすることを免れました.
C++を使用してCSVテーブルを読み取る大まかな考え方:
1:ファイルを開くようにCSVテーブルを開き、ファイルポインタの様々なウォークスルーによって各行を分割し、1行のデータを1つのstringオブジェクトに格納します.ファイルの各行をループして読み込み、ファイルの読み取りが完了するとmapのようなオブジェクトが生成され、intは行番号を表し、stringはその行のすべての文字を表す.使用する関数はstrchrです
2:さらに各行を分割し、分割の基準はカンマです.これにより、各行に対してcols個のstringオブジェクトが分割され、これらのオブジェクトもmapオブジェクトに格納され、ここでintは左から右の列番号を表し、1から数える.これにより、各行のデータが1つ生成されます.
mapオブジェクトは,テキストを処理するとmapオブジェクトを生成する.テーブル内の各フィールドを、二重マッピング関係を使用して規則的に格納します.
具体的な実装コードは次のとおりです.
ファイルから読み込まれた内容はstringオブジェクトに格納されているので、ファイルに一定の意味のデータが格納されている場合は、変換する必要があります.
CSVテーブルのルール:
1先頭は、空白を残さずに動作単位で行います.
2カラム名を含むか含まないか、カラム名を含むとファイルの最初の行になります.
3 1行のデータは崩れず、空行はない.
4は半角カンマ(すなわち、)で区切り、列が空であってもその存在を表す.
5列の内容は、半角カンマ(すなわち、)がある場合は、半角引用符(すなわち「」)でフィールド値を含めます.
6列の内容に半角引用符(すなわち「)がある場合は、半角二重引用符(」")に置き換え、半角引用符(すなわち「」)でフィールド値を含めます.
7ファイルの読み書き時の引用符、カンマの操作規則は互いに逆です.
8イントラコードフォーマットは、ASCII、Unicodeまたはその他であってもよい.
9特殊文字はサポートされていません
CSV表の用途:
CSVテーブルもリレーショナル・データベースの2 Dテーブルに相当しますが、SQL文のクエリーはサポートされておらず、いくつかの手段でテーブルの内容を適切なデータ構造に格納するだけでクエリーが容易になります.構造選択が適切であれば、クエリーは便利ですが、表のデータの更新には不利で、更新はファイルの操作のように、さまざまなファイルポインタが泳いでいて、煩雑です.もしプログラムの中で外部のデータを使うならば、データはまた多くなくてデータベースを使うならば、CSV表を使って外部のデータを保存することを考慮することができて、プログラムが実行するたびに外部からデータを読み取ってメモリに入ることができて、プログラムがデータの変更によって再コンパイルすることを免れました.
C++を使用してCSVテーブルを読み取る大まかな考え方:
1:ファイルを開くようにCSVテーブルを開き、ファイルポインタの様々なウォークスルーによって各行を分割し、1行のデータを1つのstringオブジェクトに格納します.ファイルの各行をループして読み込み、ファイルの読み取りが完了するとmap
2:さらに各行を分割し、分割の基準はカンマです.これにより、各行に対してcols個のstringオブジェクトが分割され、これらのオブジェクトもmap
map
具体的な実装コードは次のとおりです.
#pragma once
//#include "stringparser.h"
#include <assert.h>
#include <map>
#include <vector>
#include <string>
#include "SkillRecord.h"
using namespace std;
typedef unsigned long u32;
class CppCSV
{
private:
map<u32, map<u32, string>> m_stringMap;
string m_CSVName;
public:
CppCSV(){}
CppCSV(const char *path)
{
assert(LoadCSV(path));
}
~CppCSV(){}
bool LoadCSV(const char *path);
bool SaveCSV(const char *path = NULL);
bool GetIntValue(u32 uiRow, u32 uiCol, int &riValue);
bool GetFloatValue(u32 uiRow, u32 uiCol, float &rfValue);
string* GetStringValue(u32 uiRow, u32 uiCol);
int GetParamFromString(string str, vector<string> &stringVec, char delim = ',');
map<u32, map<u32, string>>& GetCSVMap()
{
return m_stringMap;
}
void GetSkillRecordMapTable(map<int, SkillRecord> &sSkillMapTable);
};
#include "CppCSV.h"
#include <stdio.h>
//#include "stringparser.h"
bool CppCSV::LoadCSV(const char *path)
{
FILE *pFile = fopen(path, "r");
if (pFile)
{
fseek(pFile, 0, SEEK_END);
u32 uSize = ftell(pFile);
rewind(pFile);
char *fileBuffer = new char[uSize];
fread(fileBuffer, 1, uSize, pFile);
map<u32, string> stringMap;
u32 uiIndex = 1;
char *pBegin = fileBuffer;
char *pEnd = strchr(pBegin, '
');
pBegin = pEnd + 1;
pEnd = strchr(pBegin, '
');
while (pEnd)
{
string strTemp;
strTemp.insert(0, pBegin, pEnd-pBegin);
assert(!strTemp.empty());
stringMap[uiIndex++] = strTemp;
pBegin = pEnd + 1;
pEnd = strchr(pBegin, '
');
}
delete []fileBuffer;
fileBuffer = NULL;
pBegin = NULL;
pEnd = NULL;
map<u32, string>::iterator iter = stringMap.begin();
for (; iter != stringMap.end(); ++iter)
{
vector<string> stringVec;
map<u32, string> stringMapTemp;
assert(GetParamFromString(iter->second, stringVec) > 0);
vector<string>::size_type idx = 0;
for (; idx != stringVec.size(); ++idx)
{
stringMapTemp[idx + 1] = stringVec[idx];
}
m_stringMap[iter->first] = stringMapTemp;
}
fclose(pFile);
m_CSVName = path;
return true;
}
else
{
return false;
}
}
bool CppCSV::SaveCSV(const char *path /* = NULL */)
{
if (path != NULL)
{
m_CSVName = path;
}
FILE *pFile = fopen(m_CSVName.c_str(), "w");
if (pFile)
{
map<u32, map<u32, string>>::iterator iter = m_stringMap.begin();
for (; iter != m_stringMap.end(); ++iter)
{
map<u32, string> &rStringMap = iter->second;
map<u32, string>::iterator it = rStringMap.begin();
for (; it != rStringMap.end(); ++it)
{
string strTemp = it->second;
strTemp += ',';
fwrite(strTemp.c_str(), 1, 1, pFile);
}
char delim = '
';
fwrite(&delim, 1, 1, pFile);
}
fclose(pFile);
return true;
}
else
{
return false;
}
}
bool CppCSV::GetIntValue(u32 uiRow, u32 uiCol, int &riValue)
{
string *pStr = GetStringValue(uiRow, uiCol);
if (pStr)
{
riValue = atoi(pStr->c_str());
return true;
}
else
{
return false;
}
}
bool CppCSV::GetFloatValue(u32 uiRow, u32 uiCol, float &rfValue)
{
string *pStr = GetStringValue(uiRow, uiCol);
if (pStr)
{
rfValue = atof(pStr->c_str());
return true;
}
else
{
return false;
}
}
string* CppCSV::GetStringValue(u32 uiRow, u32 uiCol)
{
map<u32, map<u32, string>>::iterator iter = m_stringMap.find(uiRow);
if (iter != m_stringMap.end())
{
map<u32, string> &rStrMap = iter->second;
map<u32, string>::iterator it = rStrMap.find(uiCol);
if (it != rStrMap.end())
{
return &(it->second);
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
// , CSV , vector
// CSV ,
int CppCSV::GetParamFromString(string str, vector<string> &stringVec, char delim)
{
char *token = strtok(const_cast<char *>(str.c_str()), &delim);
while (token)
{
string strTemp = token;
stringVec.push_back(strTemp);
token = strtok(NULL, &delim);
}
return stringVec.size();
}
void CppCSV::GetSkillRecordMapTable(map<int, SkillRecord> &sSkillMapTable)
{
map<u32, map<u32, string>>::iterator iter = m_stringMap.begin();
for (; iter != m_stringMap.end(); ++iter)
{
map<u32, string> strmap = iter->second;
SkillRecord skillTemp;
skillTemp.SetID(atoi(strmap[1].c_str()));
skillTemp.SetPath(strmap[2]);
skillTemp.SetName(strmap[3]);
skillTemp.SetHurt(atoi(strmap[4].c_str()));
skillTemp.SetPlayTime(atoi(strmap[5].c_str()));
sSkillMapTable[skillTemp.GetID()] = skillTemp;
}
}
テストコード: CppCSV cs("skill.csv");
map<u32, map<u32, string>> stringMap = cs.GetCSVMap();
map<u32, map<u32, string>>::iterator iter = stringMap.begin();
for (; iter != stringMap.end(); ++iter)
{
map<u32, string> strmap = iter->second;
map<u32, string>::iterator it = strmap.begin();
for (; it != strmap.end(); ++it)
{
cout<<it->second<<" ";
}
cout<<endl;
}
ファイルから読み込まれた内容はstringオブジェクトに格納されているので、ファイルに一定の意味のデータが格納されている場合は、変換する必要があります.