c++ Read from .csv file
Asked Answered
G

4

27

I have this code which is supposed to cout in console the information from the .csv file;

while(file.good())
{

    getline(file, ID, ',');
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero, ' ') ; 
    cout << "Sexo: " <<  genero<< " "  ;

}

And a csv file that has this (when I open with notepad):

0,Filipe,19,M

1,Maria,20,F

2,Walter,60,M

Whenever I run the program the console will display this:

Unexpected output

My question is why isn't the program repeating those cout messages in every line instead of only in the first one

Btw , nome is name, idade is age, and genero/sexo is gender, forgot to translate before creating this post

Geology answered 8/5, 2013 at 17:24 Comment(5)
I was looking for an easy way to do this, if possible. The link you posted is like chinese for me regarding my current knowledgeGeology
@FreemanZhang: That's C#, this is C++.Whether
@FilipeGama: You have two issues, (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated.Moolah
@Mooing Duck Yes it will, but just sometimes and can't figure out why, could you explain me where should I check if the input was valid?Geology
@FilipeGama: If you do an input operation, test if it succeeded. Streams propogate the failure though, so you only have to test if the last one succeeded, which is awesome.Moolah
M
29

You can follow this answer to see many different ways to process CSV in C++.

In your case, the last call to getline is actually putting the last field of the first line and then all of the remaining lines into the variable genero. This is because there is no space delimiter found up until the end of file. Try changing the space character into a newline instead:

    getline(file, genero, file.widen('\n'));

or more succinctly:

    getline(file, genero);

In addition, your check for file.good() is premature. The last newline in the file is still in the input stream until it gets discarded by the next getline() call for ID. It is at this point that the end of file is detected, so the check should be based on that. You can fix this by changing your while test to be based on the getline() call for ID itself (assuming each line is well formed).

while (getline(file, ID, ',')) {
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero);
    cout << "Sexo: " <<  genero<< " "  ;
}

For better error checking, you should check the result of each call to getline().

Mandiemandingo answered 8/5, 2013 at 17:51 Comment(4)
@FilipeGama: Did you try my suggested fix?Mandiemandingo
Yes, the second one worked :) Thanks, as i said in other answer I would upvote but can't because don't have enough pointsGeology
@user315052: There's two issues: (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated.Moolah
@user315052 Thanks, I've just accepted your answer for being the most complete, thanks to MooingDuck too. Gratz, still no way to upvoteGeology
B
14

a csv-file is just like any other file a stream of characters. the getline reads from the file up to a delimiter however in your case the delimiter for the last item is not ' ' as you assume

getline(file, genero, ' ') ; 

it is newline \n

so change that line to

getline(file, genero); // \n is default delimiter
Bonus answered 8/5, 2013 at 18:14 Comment(7)
Just what I wanted to write, so +1. This code doesn't look for the newline character, which leads for the rest not being parsed correctly.Wobbly
thanks that solved the problem , finally :) I'd vote you up but don't have enough points so here is my comment, gratzGeology
@FilipeGama An 'upvote' isn't the only way to say 'Thank you'. Accepting their answer is another perfectly valid way to appreciate their effort.Wobbly
np Filipe, just happy to helpBonus
@Refugnic Eternium @ claptrap Didn't know about that, already "accepted"Geology
@claptrap: There's two issues: (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated.Moolah
@Mooing Duck is right, I just realised that later...it's duplicating the last line, how should I do it then? Thanks in advance :)Geology
W
4

Your csv is malformed. The output is not three loopings but just one output. To ensure that this is a single loop, add a counter and increment it with every loop. It should only count to one.

This is what your code sees

0,Filipe,19,M\n1,Maria,20,F\n2,Walter,60,M

Try this

0,Filipe,19,M
1,Maria,20,F
2,Walter,60,M


while(file.good())
{

    getline(file, ID, ',');
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero) ; \\ diff
    cout << "Sexo: " <<  genero;\\diff


}
Worldshaking answered 8/5, 2013 at 17:24 Comment(6)
If it's not 3 loops how does it display 2nd and 3rd line (even without the couts? Sorry I'm struggling to understand these .csv concepts , thanks in advance edit: if you could edit my code and post it here I'd be very thankful :)Geology
It kinda worked but now I got this : dl.dropboxusercontent.com/u/4613740/console2.png It repeats the last line for some reason...Geology
Again that will only work well for the 1st line, the others it'll just mess up... this way : dl.dropboxusercontent.com/u/4613740/console3.pngGeology
Hadn't noticed the commas, still : dl.dropboxusercontent.com/u/4613740/console4.png Repeats the last line and inserts new lines before ID :( it's driving me nuts...Geology
I have corrected the code and the csv, (I didn't have a compiler before). The repeated lines are due to a blank line at the end of your .csvWorldshaking
@IanJenkins: Correct code would make that less of an issue: coliru.stacked-crooked.com/…Moolah
T
-6

That because your csv file is in invalid format, maybe the line break in your text file is not the \n or \r

and, using c/c++ to parse text is not a good idea. try awk:

 $awk -F"," '{print "ID="$1"\tName="$2"\tAge="$3"\tGender="$4}' 1.csv
 ID=0   Name=Filipe Age=19  Gender=M
 ID=1   Name=Maria  Age=20  Gender=F
 ID=2   Name=Walter Age=60  Gender=M
Topdrawer answered 8/5, 2013 at 17:47 Comment(3)
thanks for the answer although I have no idea how awk works, do you know of any useful link about that?Geology
And seems you're using Windows. here's GAWK for WindowsTopdrawer
Thanks again for all the help, but already working anyway :)Geology

© 2022 - 2024 — McMap. All rights reserved.