Fourth Tool class: Csvreader
Csvreader is used to support reading CSV tables.
CSV format is actually a fixed format of txt, a row of each column in English ', ' separated
There are many game static tables in the game project. The plan provides a CSV form that can be easily edited with Excel. Client unity also tends to read CSV tables, plain text, simple format, easy to read
Then for the sake of reading more convenient, we have defined the CSV first 3 lines of content has special significance, the following figure is an example
Column name for each of the first row
Each column of the second row is of type
Each column in the third row contains a description of the name in Chinese
Line four starts with the actual data
Specify the supported column types
4 Basic types:
U: corresponds to unsigned int
I: corresponding int
F: corresponds to float
S: corresponding std::string
substructure: If the column is a sub-structure, specify the field name and field type of the sub-structure, in English semicolon '; ' Segmentation
As shown above in the structid;u; Structnum;i; Structfloat;f; Strucename;s:
Indicates that the substructure has 4 fields: structid,unsigned int type, structnum,int type, structfloat,float type, Strucename, String type
Segmentation of the actual data between the neutron structure fields in English and the operator ' & '
As in the figure above, 1&-2&3.4&AAA:
Represents STRUCTID=1,STRUCTNUM=-2,STRUCTFLOAT=3.4F,STRUCENAME=AAA, {1,-2, 3.4f, "AAA"}
Qualified type of column type:
K: Indicates that the column is a primary key and is used as an index
Supports up to 3 column primary keys, or 3 columns combined to determine a unique row of records
The primary key is not necessarily in the first 3 columns, you can use some of the middle columns
The type of the primary key is qualified as an integer, that is, the column type after k is I or u
LST: Indicates that the column is a variable-length array
As listed above, Lst:u:
Indicates that the column is an array of unsigned int, which corresponds to std::vector<unsigned int>
As in the above example, lst:structid;u; Structnum;i; Structfloat;f; Strucename;s:
An array that indicates that the column is a sub-structure
The actual data in the array between the elements and elements in English semicolon '; ' Segmentation
As in the example above 1&-2&3.4&AAA;5&-6&7.8&BBB:
Indicates that the sub-structure array has 2 elements, the first element is {1,-2, 3.4f, "AAA"}, the second element is {5,-6, 7.8f, "BBB"}
K or LST followed by the English colon ":" followed by the specific column type
The above is a man-made rule
So for a table like this, the structure that reads into memory corresponds to the following:
Class Struct
{public
:
unsigned int m_structid;
int m_structnum;
float m_structfloat;
std::string m_strucename;
};
Class Test
{public
:
unsigned int m_id1; Test PRIMARY key 1
int m_id2; Test PRIMARY key 2
unsigned int m_id3; Test PRIMARY Key 3
std::string m_str; Test string
std::vector<unsigned int> m_uints; Test number list
float m_float; Test the digital
Struct m_struct; Test sub-structure
std::vector<struct> m_structlists; Test sub-structure list
};
The csvreader of this paper is a tool class to read the corresponding class object in order to realize the CSV file which is specified in the above-described format.
The next article will write a code auto-generation tool that automatically generates code for the class object corresponding to each table
(Because the plan to modify the table structure is very frequent, the table structure once modified, the corresponding class structure will be modified, simply automatically generate trouble)
Csvreader provides several interfaces:
1, ReadLine, read a line of content, read into a cache, in CSV format reserved delimiter comma ', ', divided into the value of each column
Here is a file encoding problem, that is, under Windows, Utf8 format file has a BOM header, that is, the first 3 bytes of the file is 0XEF,0XBB,0XBF need to filter out, the line at the end of the ' \ R ', ' \ n ', need to filter out
2, Checkline, check the number of columns separated by a comma, and whether the column name of the first row is the same as the number of columns
If not, the actual data, especially the string type of the column, there is a comma in English, but the comma is a CSV file reserved delimiter
So if there is a comma in the actual data, there is no way to determine which column corresponds to which column.
3, Name2index, according to the column name, returns the column is the first column, the top 0
4, GetValue, read the value of column of single field type (non-array)
5, Getvaluelist, reading the value of the array column
6, LoadFile, load the specified file, and process the first 3 lines of content, identify the column name, and the number of columns
For sub-structures, the substructure overload assignment operator is required and the argument is a string, as
xxx& operator = (const std::string &other) for parsing a string like "1&-2&3.4&aaa" in the previous example
It also uses the previously mentioned Stringtool, which is used for string segmentation, and whether the checksum is a valid number
On the Code
CsvReader.h
#ifndef __csvreader_h__ #define __CSVREADER_H__ #include <string> #include <vector> #include <map> #in Clude <fstream> #include "StringTool.h" namespace common{namespace tool{class Csvreader {public:csv
Reader ();
~csvreader ();
CSV file opens bool OpenFile (const std::string& file_path_name);
CSV file opens and processes the first 3 rows of data bool LoadFile (const std::string& file_path_name);
Reads a row of data (the first line to the BOM, the end of each line line newline character) size_t ReadLine (bool Firstline = false);
After reading a row of data, get the original contents of each column const std::vector<std::string>& GetLine ();
Check whether the number of columns matches the number of column names bool Checkline ();
The column number is obtained according to the column name, the first column is numbered 0 size_t name2index (const std::string& name); Take the value of a column of the current row bool Getvaluelist (size_t index, std::vector<std::string>& values, const std::string& split)
;
BOOL GetValue (size_t index, std::string& value);
BOOL Getvaluelist (size_t index, std::vector<unsigned int>& values, const std::string& split);BOOL GetValue (size_t index, unsigned int& value);
BOOL Getvaluelist (size_t index, std::vector<int>& values, const std::string& split);
BOOL GetValue (size_t index, int& value);
BOOL Getvaluelist (size_t index, std::vector<float>& values, const std::string& split);
BOOL GetValue (size_t index, float& value); Template <class t> bool Getstructlist (size_t index, std::vector<t>& values, const std::string& SPLI
T);
Template <class t> bool Getstruct (size_t index, t& value);
Private://File input stream Std::ifstream m_file;
Column name <-> column subscript mapping table std::map<std::string, size_t> m_names;
The value of each column of the current row std::vector<std::string> m_values;
}; Template <class t> bool Csvreader::getstructlist (size_t index, std::vector<t>& values, const Std::strin
g& split) {if (Index < m_values.size ()) {std::vector<std::string> tempstrs; Stringtool:: Splitstr2list (M_values[index], split, tempstrs);
for (size_t i = 0; i < tempstrs.size (); i++) {if (tempstrs[i].length () > 0) {t tempt;
tempt = Tempstrs[i];
Values.push_back (tempt);
}} return true;
} else {return false; }} template <class t> bool Csvreader::getstruct (size_t index, t& value) {if (Index < M_VALUES.S
Ize ()) {value = M_values[index];
return true;
} else {return false; }}} #endif
CsvReader.cpp
#include "CsvReader.h" #include <string.h> namespace common{namespace tool{const unsigned int maxlinelen = 1
0240;
Const std::string csvsplit = ",";
Csvreader::csvreader () {m_names.clear ();
M_values.clear ();
} csvreader::~csvreader () {m_names.clear ();
M_values.clear ();
if (m_file) {m_file.close ();
}} size_t Csvreader::readline (bool firstline) {if (m_file) {char Line[maxlinelen];
memset (line, 0x00, sizeof (char) * maxlinelen);
M_file.getline (line, Maxlinelen);
size_t len = strlen (line);
Remove first line BOM if (3 <= len) {if (firstline) {if (0xEF = = (unsigned char) line[0] && 0xBB = = (unsigned char) line[1] && 0xBF = = (unsigned char) line[2] {memcpy (line, line + 3, l
En + 1-3);
len = len-3; }}}//Remove the end of each line \ r \ n while (1 <= len) {if (' \ r ' = = Line[len-1] | |
' \ n ' = = Line[len-1]) { Line[len-1] = ' + ';
len = len-1;
} else {break;
}} if (0 < len) {m_values.clear ();
Stringtool::splitstr2list (line, Csvsplit, m_values);
} return len;
} else {return 0;
}} const std::vector<std::string>& Csvreader::getline () {return m_values;
} bool Csvreader::checkline () {if (m_values.size () = = M_names.size ()) {return true;
} else {return false; }} bool Csvreader::openfile (const std::string& file_path_name) {M_file.open (File_path_name.c_str (), std::i
Os::in);
if (M_file) {return true;
} else {return false; }} bool Csvreader::loadfile (const std::string& file_path_name) {M_file.open (File_path_name.c_str (), std::i
Os::in);
if (m_file) {//Read column name ReadLine (TRUE); Save column names, use for field validation, and subscript for column names for (size_t i = 0; i < m_values.size (); i++) {M_names[stringtool:: Upcasefirstchar (m_values[i])] = i;
}//Read column type ReadLine ();
Read comment ReadLine ();
return true;
} else {return false; }} size_t Csvreader::name2index (const std::string& name) {std::map<std::string, size_t>::iterator it
= M_names.find (name);
if (it = M_names.end ()) {return it->second;
} else {return-1; }} bool Csvreader::getvaluelist (size_t index, std::vector<std::string>& values, const std::string& SPL It) {if (Index < m_values.size ()) {if (0 < M_values[index].length ()) {stringtool::splitstr2l
IST (M_values[index], split, values);
} return true;
} else {return false; }} bool Csvreader::getvalue (size_t index, std::string& value) {if (Index < m_values.size ()) {VA
Lue = M_values[index];
return true;
} else {return false; }} bool Csvreader::getvaluelist (size_t index, STD::Vector<unsigned int>& values, const std::string& split) {if (Index < m_values.size ()) {if (0
< M_values[index].length ()) {return stringtool::splitstr2list (M_values[index], split, values);
} return true;
} else {return false; }} bool Csvreader::getvalue (size_t index, unsigned int& value) {if (Index < m_values.size ()) {I
F (Stringtool::isuint (M_values[index])) {value = static_cast<unsigned int> (atoi (M_values[index].c_str ()));
return true;
} else {return false;
}} else {return false;
}} bool Csvreader::getvaluelist (size_t index, std::vector<int>& values, const std::string& split) { if (Index < m_values.size ()) {if (0 < M_values[index].length ()) {return Stringtool::splitstr2li
St (M_values[index], split, values);
} return true;
} else {return false; }} bool CSvreader::getvalue (size_t index, int& value) {if (Index < m_values.size ()) {if (Stringtool::isint (m_v
Alues[index]) {value = Atoi (M_values[index].c_str ()));
return true;
} else {return false;
}} else {return false;
}} bool Csvreader::getvaluelist (size_t index, std::vector<float>& values, const std::string& split) {if (Index < m_values.size ()) {if (0 < M_values[index].length ()) {return STRINGTOOL::SPLITSTR2
List (M_values[index], split, values);
} return true;
} else {return false; }} bool Csvreader::getvalue (size_t index, float& value) {if (Index < m_values.size ()) {if (stri
Ngtool::isfloat (M_values[index])) {value = Static_cast<float> (Atof (M_values[index].c_str ()));
return true;
} else {return false;
}} else {return false; }
}
}
}