I am trying to count the number of rows in a .csv file however I have repeatedly run into a problem while running it where it will work until the 2nd to last line and then return an error
1 2
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 2179) >= this->size() (which is 2179)
I've tried multiple different things and they have all resulted in the same error. This is my current code:
1 2 3 4 5 6 7 8 9 10 11 12 13
while (!fileInput.eof()){
temp = doc.GetRow<std::string>(j); //grab a row and store it temporarily (has to be stored due to nature of rapidcsv .GetRow)
allData.push_back(fill_allData(temp)); //puts row in vector
j++;//increase count.
}
for (int i = 0; i < allData.size(); i++){
std::cout << allData[i] << std::endl;
}
Just an observation. eof() is set when an attempt to read data fails. It's not set after an operation. So reading the last row from the file will not set .eof() but attempting to read another row will.
with <filesystem> you can read all the bytes (using the file's size) and stop (not one by one, track what you read!), if using the while ( file>>variable) paradigm is not sufficient. That can get funky using streams because of the whitespace, just be sure you count accurately or use the file pointer position or something like that.
most text files though you just say
while(file >> variable)
if you control the file writing, for text files, its very useful to just dump the counts up front, eg number of rows or number of entries etc as the first value in the file, read that and then iterate that many times.
Also, you're not showing the code that throws the exception.
On the actual test, don't treat files as files if you don't have to, the object treats them as streams. A stream has states good, bad and failed. You want to keep processing while it's good. The typically looks like:
Do not loop on (! stream.eof()) or (stream.good()). This does not work the way you expect. The eof bit is set true only after you make a read attempt on the file. This means after you read the last record of the file, eof is still false. Your attempt to read past the last record sets eof, but you're not checking it there. You proceed as if you had read a good record. This will result in reading an extra (bad) record. The correct way to deal with this is to put the >> (or getline) operation as the condition in the while statement.
1 2 3
while (stream >> var) // or while (getline(stream,var))
{ // Good operation
}
@kbw, I'm sorry I'm not entirely sure I understand. That code does use fileInput, and it is what throws the exception. I've stepped through it using gdb and the exception is thrown during the while loop. However, I accept I could be wrong, and I definitely should have included the initialization of variables. Here is the entire function:
bool read_File(constchar* fileName, std::vector <Entry> allData){
//create temp vector to add file data into before adding it to struct vect.
std::vector <std::string> temp;
int row = 0, j = 0;
char currChar;
std::string tempLine;
std::ifstream fileInput;
fileInput.open(fileName);
//make sure the file opens
//return error if it doesn't, start unpacking if it is
if (fileInput.is_open()){
//open the doc and set specifications.
//LabelParams(columnHeader,rowHeader) 0 = true, -1 = false
//SeparatorParams(delimiter, trim, hasCR, quoted line break, remove quotes from cells)
rapidcsv::Document doc(fileName, rapidcsv::LabelParams(0,-1), rapidcsv::SeparatorParams(',', false, rapidcsv::sPlatformHasCR, true, false));
//traverse file
while (fileInput >> tempLine){
temp = doc.GetRow<std::string>(j); //grab a row and store it temporarily (has to be stored due to nature of rapidcsv .GetRow)
allData.push_back(fill_allData(temp)); //puts row in vector
j++;//increase count.
}
for (int i = 0; i < allData.size(); i++){
std::cout << allData[i] << std::endl;
}
returntrue;
}
returnfalse;
}
@AbstractionAnon (love the user name btw)
Ok, for sure! I like the while(stream >> var) . It's getting closer to the end of the file, but it is still throwing the error. When I run it, it still outputs the std::out_of_range . Am I applying your suggestion wrong?