难以用C++读取复杂的.csv文件



我正在尝试读取.csv文件并将其存储在结构向量中。目前,我的程序工作在一个更小、更简单的文件上,但没有扩大规模。目前我的主要问题是错误";错误:对"getline(std::string&,char("的调用没有匹配的函数30|getline(e.ea,','("尽管我在试着传球。

我试着直接将输入输入到向量中,而不是使用getline,但它很快就变得非常复杂,我完全是个初学者。

这是我的代码:

#include <string>
#include <fstream>
#include <iomanip>
#include <vector>
#include <sstream>
using namespace std;
struct Entry {
string eb, ed, ee, ef, eh, ei, ej, el, ek, em, en, er, es, et, eu, ev, ew, ex, ey, ez, ea, eg, ec, eo, ep, eq;

friend ostream& operator<<(ostream& os, const Entry e);
friend istream& operator>>(istream& is, Entry& e);

};
Entry parse_Line(ifstream &source);
bool read_File(const char*);
void write_File(vector <Entry>& data);
//overloading operator << and >> to be able to print out the information needed.
ostream& operator<<(ostream& os, const Entry e)
{
os << "d: " << e.ed << " e: " << e.ee << " f: " << e.ef << " h: " << e.ei << " m: " << e.em << "n";
return os;
}
istream& operator>>(istream& is, Entry& e){
getline(e.ea, ',');
getline(is >> ws, e.eb, ',');
getline(is >> ws, e.ec, ',');
getline(is >> ws, e.ed, ',');
getline(is >> ws, e.ee, ',');
getline(is >> ws, e.ef, ',');
getline(is >> ws, e.eg, ',');
getline(is >> ws, e.eh, ',');
getline(is >> ws, e.ei, ',');
getline(is >> ws, e.ej, ',');
getline(is >> ws, e.ek, ',');
getline(is >> ws, e.el, ',');
getline(is >> ws, e.em, ',');
getline(is >> ws, e.en, ',');
getline(is >> ws, e.eo, ',');
getline(is >> ws, e.ep, ',');
getline(is >> ws, e.eq, ',');
getline(is >> ws, e.er, ',');
getline(is >> ws, e.es, ',');
getline(is >> ws, e.et, ',');
getline(is >> ws, e.eu, ',');
getline(is >> ws, e.ev, ',');
getline(is >> ws, e.ew, ',');
getline(is >> ws, e.ex, ',');
getline(is >> ws, e.ey, ',');

return(is >> e.ez);
} 

Entry parse_Line(ifstream& source){
string eb, ed, ee, ef, eh, ei, ej, el, ek, em, en, er, es, et, eu, ev, ew, ex, ey, ez, ea, eg, ec, eo, ep, eq;
Entry tempEntry;

//scan a line from the file
source >> ea >> eb >> ec >> ed >> ef >> eg >> eh >> ei >> ej >> ek >> el >> em >> en >> eo >> ep >> eq >> er >> es >> et >> eu >> ev >> ew >> ex >> ey >> ez;

/*while(getline(str, word, ','))
row.push_back(word);
content.push_back(row);*/


//assign data to tempEntry
tempEntry.ea = ea;
tempEntry.eb = eb;
tempEntry.ec = ec;  
tempEntry.ed = ed;
tempEntry.ee = ee;
tempEntry.ef = ef;
tempEntry.eg = eg;
tempEntry.eh = eh;
tempEntry.ei = ei;
tempEntry.ej = ej;
tempEntry.ek = ek;
tempEntry.el = el;
tempEntry.em = em;
tempEntry.en = en;
tempEntry.eo = eo;
tempEntry.ep = ep;
tempEntry.eq = eq;
tempEntry.er = er;
tempEntry.es = es;
tempEntry.et = et;
tempEntry.eu = eu;
tempEntry.ev = ev;
tempEntry.ew = ew;
tempEntry.ex = ex;
tempEntry.ey = ey;
tempEntry.ez = ez;
return tempEntry;
} 
bool read_File(const char* fileName, vector <Entry>& allData){
//take in file name and name of struct created to store data.
string line;

ifstream fileInput;
fileInput.open(fileName, ios::in);

if (fileInput.is_open()){
// take each line, put it into the parse_Line function, then put it into the allData vector.
for (Entry e; fileInput >> e; allData.push_back(move(e)));

fileInput.close();


write_File(allData);
return true;
} else {
return false;
}

}
void write_File(vector <Entry>& data){
//use vector passed in and print it to console for now. will change to printing a new csv file
for (int i=0; i<=data.size(); i++ ){
cout << data[i] << " ";
}

return;
}
int main (int argc, char* argv[]) {
//check for file
if (argc < 2){
return(cout << "No file name specifiedn"),1;
}
//read in file name to a function using following:
string str(argv[1]);
vector <Entry> data;

if (!read_File(argv[1], data)){
return(cout << "That file name is invalidn"), 2;
}

const char* nameStr = str.c_str();
read_File(nameStr, data);

return 0;
} 

这是我输入文件的简化版本(实际的文件在每个条目中都有段落(。

3902,字符串1,3,字符串2,字符串3,字符串4,字符串5,230,字符串6,字符串7,字符串8,字符串9,字符串ten,字符串11,字符串12,字符串13,43,34,89,字符串14,字符串15,字符串16,字符串17,字符串18,字符串19,字符串20,字符串21,字符串22

92,b,324,c,d,e,f,g,h,i,j,k,l,m,n,43l,93403392,r,s,t,u,v,w,x,y,z

您的错误阻止编译,因为只有两个getline(),而operator>>的第一行与这两行中的任何一行都不匹配:

  • std::getline(),这是一个需要isteam&作为第一参数的自由函数
  • std::istream::getline(),它是istream的成员函数,并且只能读入已知大小的字符数组

所以:

istream& operator>>(istream& is, Entry& e){
getline(e.ea, ',');
...

只能是

getline (is, e.ea, ',');   // or is>>ws

不幸的是,你的方法有缺陷。这里的主要问题是isis>>ws占用空白,这些空白不仅是",而且是换行符。这意味着,如果文件中缺少某些字段,或者某些字段过多,您很快就会在错误的行中读取错误的信息。

更糟糕的是,getline(is,...,',')只会停止一个逗号,并在字符串中保留换行符,就好像它是另一个字符一样。同样,如果输入文件遗漏了一些字段,您可能会在错误的行中读取错误的信息。

csv文件格式是由行驱动的,所以你应该做的最好的事情是实现一个永远不会错过换行的算法。通常的tric是使用getline()读取整行,然后使用istringstream解析该字符串中的字段。这样,如果输入文件中有错误,您可以很容易地发现它,并且不会陷入不匹配。

现在,如果您需要完全支持符合RFC 4180的csv,那就更复杂了:您必须支持可以包含换行符的引号,然后该换行符将被视为带引号字段的字符。这将需要更复杂的解析,逐个字符读取并管理引号状态,以正确解析字段,如果包含在引号中,则忽略逗号和换行符。

我决定使用d99kris等人的rapidCSV。虽然我很想能够发布我的问题的直接解决方案以供将来参考,但当rapidCSV单头可以完成我需要做的事情时,重新发明轮子是没有意义的。

最新更新