C++导入导出CSV文件
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void csvline_populate(vector<string> &record, const string& line, char delimiter);
int main(int argc, char *argv[])
{
vector<string> row;
string line;
ifstream in("input.csv");
if (in.fail()) { cout << "File not found" <<endl; return 0; }
while(getline(in, line) && in.good() )
{
csvline_populate(row, line, ',');
for(int i=0, leng=row.size(); i<leng; i++)
cout << row[i] << "\t";
cout << endl;
}
in.close();
return 0;
}
void csvline_populate(vector<string> &record, const string& line, char delimiter)
{
int linepos=0;
int inquotes=false;
char c;
int i;
int linemax=line.length();
string curstring;
record.clear();
while(line[linepos]!=0 && linepos < linemax)
{
c = line[linepos];
if (!inquotes && curstring.length()==0 && c=='"')
{
//beginquotechar
inquotes=true;
}
else if (inquotes && c=='"')
{
//quotechar
if ( (linepos+1 <linemax) && (line[linepos+1]=='"') )
{
//encountered 2 double quotes in a row (resolves to 1 double quote)
curstring.push_back(c);
linepos++;
}
else
{
//endquotechar
inquotes=false;
}
}
else if (!inquotes && c==delimiter)
{
//end of field
record.push_back( curstring );
curstring="";
}
else if (!inquotes && (c=='\r' || c=='\n') )
{
record.push_back( curstring );
return;
}
else
{
curstring.push_back(c);
}
linepos++;
}
record.push_back( curstring );
return;
}
http://www.zedwood.com/article/112/cpp-csv-parser#include <fstream>
#include <string>
#include <vector>
using namespace std;
void csvline_populate(vector<string> &record, const string& line, char delimiter);
int main(int argc, char *argv[])
{
vector<string> row;
string line;
ifstream in("input.csv");
if (in.fail()) { cout << "File not found" <<endl; return 0; }
while(getline(in, line) && in.good() )
{
csvline_populate(row, line, ',');
for(int i=0, leng=row.size(); i<leng; i++)
cout << row[i] << "\t";
cout << endl;
}
in.close();
return 0;
}
void csvline_populate(vector<string> &record, const string& line, char delimiter)
{
int linepos=0;
int inquotes=false;
char c;
int i;
int linemax=line.length();
string curstring;
record.clear();
while(line[linepos]!=0 && linepos < linemax)
{
c = line[linepos];
if (!inquotes && curstring.length()==0 && c=='"')
{
//beginquotechar
inquotes=true;
}
else if (inquotes && c=='"')
{
//quotechar
if ( (linepos+1 <linemax) && (line[linepos+1]=='"') )
{
//encountered 2 double quotes in a row (resolves to 1 double quote)
curstring.push_back(c);
linepos++;
}
else
{
//endquotechar
inquotes=false;
}
}
else if (!inquotes && c==delimiter)
{
//end of field
record.push_back( curstring );
curstring="";
}
else if (!inquotes && (c=='\r' || c=='\n') )
{
record.push_back( curstring );
return;
}
else
{
curstring.push_back(c);
}
linepos++;
}
record.push_back( curstring );
return;
}
6.2.4 CSV文件的读取
CSV即Comma Separated Values(以逗号分隔的值),这种文件格式经常用来作为不同程序之间的数据交互的格式。具体文件格式如下。
每条记录占一行。
记录间的值以逗号为分隔符。
逗号前后的空白字符会被忽略。
如果值中包含逗号、换行符、空格、双引号,则该值必须用双引号引起来。
值中的双引号用两个双引号表示。
如下是一段标准的CSV数据,它来自于某次科学实验的采集记录:
- 1993,124,0,13.9,11.2,7.9,5.2,3.7,2.8,2.7,3.0,0.0,0.0
- 1993,125,1,14.2,11.4,8.0,5.3,3.8,2.8,2.7,3.0,0.0,0.0
- 1993,126,2,14.4,11.7,8.2,5.4,3.9,2.8,2.7,3.0,0.0,0.0
- 1993,127,3,13.7,11.1,7.7,5.1,3.6,2.6,2.6,2.9,0.0,0.0
- 1993,128,4,12.9,10.4,7.2,4.7,3.3,2.4,2.4,2.8,0.0,0.0
- 1993,129,5,12.1,9.7,6.6,4.2,2.9,2.2,2.3,2.7,0.0,0.0
- 1993,130,6,12.3,9.9,6.8,4.3,3.0,2.2,2.3,2.7,0.0,0.0
- 1993,131,7,12.0,9.6,6.6,4.2,2.9,2.1,2.2,2.7,0.0,0.0
- 1993,132,8,12.6,10.1,7.0,4.5,3.1,2.2,2.3,2.7,0.0,0.0
将该段数据保存为某个文件,如:test.csv。Microsoft Excel支持CSV文件格式,图6-12示出在Microsoft Excel中打开test.csv的情形。
(点击查看大图)图6-12 在Microsoft Excel中打开test.csv |
现在动手
下面我们使用文件流来实现一个CSV文件的读取程序。
选择【Win32】→【Win32项目】→【控制台程序】命令,创建CsvParser。
创建CRow类,它用来描述每一个行的记录。该类实际上是一个CStringArray的代理类:
- class CRow
- {
- private:
- CStringArray * _row;
- public:
- CRow(CStringArray * row);
- int getColumnCount(void);
- CString getColumn(int i);
- };
- CRow::CRow(CStringArray * row)
- {
- _row = row;
- }
- int CRow::getColumnCount(void)
- {
- return _row->GetCount();
- }
- CString CRow::getColumn(int i)
- {
- return _row->GetAt(i);
- }
创建CSheet类,它用来描述一张表格:
- class CSheet
- {
- private:
- CTypedPtrArray<CPtrArray, CStringArray *> _rows;
- public:
- CSheet(void);
- ~CSheet(void);
- int loadFrom(ifstream & in);
- int getRowCount(void);
- CRow getRow(int i);
- };
- CSheet::CSheet()
- {
- }
- CSheet::~CSheet()
- {
- for(int i = 0; i < _rows.GetCount(); i++)
- {
- delete _rows.GetAt(i);
- }
- }
- int CSheet::loadFrom(ifstream & in)
- {
- int lines = 0;
- while(!in.eof())
- {
- //读取其中的一行
- char line[256] = {0};
- in.getline(line, 255);
- CString s = line;
- //空白行,跳过
- if(s.IsEmpty())
- continue;
- //#为注释标记,跳过
- if(s[0] == '#')
- continue;
- CStringArray *pRow = new CStringArray();
- int i = 0;
- CString token = s.Tokenize(_T(",\t"), i);
- while (token != _T(""))
- {
- pRow->Add(token);
- token = s.Tokenize(_T(",\t"), i);
- }
- _rows.Add(pRow);
- lines++;
- }
- return lines;
- }
- int CSheet::getRowCount(void)
- {
- return _rows.GetCount();
- }
- CRow CSheet::getRow(int i)
- {
- return CRow(_rows.GetAt(i));
- }
修改主程序如下:
- #include "stdafx.h"
- #include "sheet.h"
- #include <iostream>
- #include <fstream>
- using namespace std;
- int main()
- {
- CSheet sheet;
- //打开csv文件
- ifstream in("test.csv");
- //加载至CSheet
- sheet.loadFrom(in);
- for(int i = 0; i < sheet.getRowCount(); i++)
- {
- _tprintf(_T("[%02d] "), i);
- //获取指定行
- CRow row = sheet.getRow(i);
- for(int j = 0; j < row.getColumnCount(); j++)
- {
- //获取指定列
- CString s = row.getColumn(j);
- _tprintf(_T("%s/"), s);
- }
- _tprintf(_T("\r\n"), i);
- }
- return 0;
- }
运行结果如图6-13所示。
(点击查看大图)图6-13 运行结果 |
当然,本程序考虑的情况还是不够完善的,希望读者能够结合该实例完善CSV文本文件的解析。
http://book.51cto.com/art/200908/145788.htm