Trouble reading CSV file

Hello!..

I have .csv file that I'm reading from that looks something like this, for example:

0,0,0,4,4,3
1,2,0,0,2,2
0,0,2,2,0,-1

I'm using std::getline() to read from my file:

1
2
3
4
5
6
7
8
9
10
while( csvFile.good() )
{
   std::string line;
   std::getline( csvFile, line, ',' );
   
   // I'm storing the values in a std::string vector individually
   // to convert them to int later on with std::stoi()
   vec_csv_str_values.push_back( line );
   line.clear();
}


The problem here is that std::getline() is kind of like appending the newline character '\n' to the last numbers of each row, so for example between the first and second row when I store the value within the std::string vector that slot ends up looking something like this:

3\n1

I just need to store the actual values though. So I would need to either ignore that newline character or add it into the std::vector by itself I think?

How could I do either one of those things?
Thanks!!
Last edited on
Why are you using getline() to read a bunch of numbers? Why not just read the numbers as numbers instead?

getline() reads until either a line-break or the end of the file is reached. In the former case, the line-break is returned as a part of the line. You could easily remove the last character, if it is a line-break, though.

Anyway, is the number of columns fixed per line? If so, then you could do something like:
1
2
3
4
int a, b, c, d, e, f;
while (fscanf(file, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, %f) == 6) {
    doSomething(a, b, c, d, e, f); // <-- process numbers!
}

Note: The fscanf() function skips (ignores) any white-space characters, including line-breaks.


Alternatively, if the number of columns may vary, you can do:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char buffer[1024];
while (fgets(file, buffer, 1024)) {
    char *str, *state;
    // Remove any trailing line-break characters
    size_t len = strlen(buffer);
    while ((len > 0) && (buffer[len-1] == '\n')) {
        buffer[--len] = '\0';
    }
    // Split current line at each ',' character
    str = strtok_r(buffer, ",", &state);
    while (str) {
        doSomething(atoi(str)); // <-- process next number!
        str = strtok_r(NULL, ",", &state);
    }
}

BTW: Probably atoi() doesn't even require the line-break to be removed explicitely.
Last edited on
getline() reads until either a line-break or the end of the file is reached.

Actually getline() reads until either the specified delimiter, which is a newline by default, encountered or the end of file is reached. In the OP the delimiter has been specified is a ',' not the newline character. Also getline() extracts and discards the delimiter.

Why are you using cstdio input instead of iostreams which are preferred in C++.



Why are you using cstdio input instead of iostreams which are preferred in C++.

Call me a *printf() and *scanf() fanboy 😅
It really looks more like you're a C fanboy.
Ok I can see now how these things work a little bit better... How would I go about reading only the numbers within my file then?
You could use the fscanf() function, as in my sample code above.

Another option (i.e. the C++ way) would be using the >>(int& val) operator of the std::ifstream class.

Be aware that >>(int& val) "extracts" a number from the stream (it also skips any leading spaces), but then you still have to read/skip the ',' character that follows before you can "extract" the next number.

See here for details:
https://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Last edited on
Gotcha, gonna look into it, thanks a lot
Good grief, such random. @brianbathorycpp, you are very close. Just a couple of tweaks to make it work correctly:

1
2
3
4
#include <iostream>
#include <sstream>
#include <string>
#include <vector> 
1
2
3
4
5
6
7
8
9
10
std::string record;
while (getline( csvFile, record ))
{
   std::string field;
   std::istringstream record_stream( record );
   while (getline( record_stream, field, ',' ))
   {
      vec_csv_str_values.push_back( field );
   }
}

Hope this helps.
Last edited on
1
2
3
4
5
for (std::string record; std::getline(csvFile, record);) {
	std::istringstream record_stream(record);

	for (std::string field; std::getline(record_stream, field, ','); vec_csv_str_values.push_back(field));
}

Works perfectly now. Thank you all for the help, really appreciate it.
Topic archived. No new replies allowed.