Reading from CSV file with C++ - c++

I was trying to read the records from a CSV file. This code is froom GeeksforGeeks. I tried compiling it. Then when I try to run it terminates with an exception
void read_record()
{
// File pointer
fstream fin;
// Open an existing file
fin.open("reportcard.csv", ios::in);
// Get the roll number
// of which the data is required
int rollnum, roll2, count = 0;
cout << "Enter the roll number "
<< "of the student to display details: ";
cin >> rollnum;
// Read the Data from the file
// as String Vector
vector<string> row;
string line, word, temp;
while (fin >> temp) {
row.clear();
// read an entire row and
// store it in a string variable 'line'
getline(fin, line);
// used for breaking words
stringstream s(line);
// read every column data of a row and
// store it in a string variable, 'word'
while (getline(s, word, ',')) {
// add all the column data
// of a row to a vector
row.push_back(word);
}
// convert string to integer for comparision
roll2 = stoi(row[0]);
// Compare the roll number
if (roll2 == rollnum) {
// Print the found data
count = 1;
cout << "Details of Roll " << row[0] << " : \n";
cout << "Name: " << row[1] << "\n";
cout << "Maths: " << row[2] << "\n";
cout << "Physics: " << row[3] << "\n";
cout << "Chemistry: " << row[4] << "\n";
cout << "Biology: " << row[5] << "\n";
break;
}
}
if (count == 0)
cout << "Record not found\n";
}
Program terminates with a message
terminate called after throwing an instance of 'std::invalid_argument'
what(): stoi"

your current error is that row[0] is not a string. stoi expects a string. invalid argument means the value you gave a function inside the parenthesis is not the value that the computer expects. i might try printing the variable of one line and checking the type with
cout << typeid(row[0]).name.()
It also is best practice to do things incrementally when coding (walk before you can run.) try reading in one cell and closing if youre struggling with that. then one line. then multiple lines. its easy enough to comment out lines of code. many text editor even have a hotkey to comment out lines of code. try googling
block comment hotkey [your text editor name]

void read_record()
{
// File pointer
fstream fin;
// Open an existing file
fin.open("reportcard.csv", ios::in);
// Get the roll number
// of which the data is required
int rollnum, count = 0;
cout << "Enter the roll number "
<< "of the student to display details: ";
cin >> rollnum;
ostringstream roll2;
roll2 << rollnum;
string roll = roll2.str();
//cout << roll;
// Read the Data from the file
// as String Vector
vector<string> row;
string line, word, temp;
while (!fin.eof()) {
row.clear();
// read an entire row and
// store it in a string variable 'line'
getline(fin, line);
// used for breaking words
stringstream s(line);
// read every column data of a row and
// store it in a string variable, 'word'
while (getline(s, word, ',')) {
// add all the column data
// of a row to a vector
row.push_back(word);
}
// convert string to integer for comparision
//roll2 = stoi(row[0]);
//cout << row[0] << row[1] << row[2] << row[3] << row[4] << row[5] << "\n";
// Compare the roll number
if (roll == row[0]) {
// Print the found data
count = 1;
cout << "Details of Roll " << row[0] << " : \n";
cout << "Name: " << row[1] << "\n";
cout << "Maths: " << row[2] << "\n";
cout << "Physics: " << row[3] << "\n";
cout << "Chemistry: " << row[4] << "\n";
cout << "Biology: " << row[5] << "\n";
break;
}
}
if (count == 0)
cout << "Record not found\n";
}

Related

I'm using a nested while loop to Parse a text file with multiple lines but for some reason, it only goes through the first line and I don't know why

I'm using a nested while loop to Parse a text file with multiple lines but for some reason, it only goes through the first line and I don't know why.
string file;
string line;
cout << "Whats the file name?" << endl;
cin >> file;
string inputStr;
string buf; // Have a buffer string
stringstream s; // create the string stream
int field = 0;
string input; //string for the input (i.e. name, ID, etc.)
ifstream InFile(file.c_str());
if (InFile.is_open()) {
cout << "File found" << endl;
while (getline(InFile, line)) {
cout << line << endl;
inputStr = line;
s << inputStr; //put the line into the stream
while (getline(s, input, ' ')) { //gets a string from the stream up the next comma
field++;
cout << " field" << field << " is " << input << endl;
}
cout << "DONE" << endl;
}
Declare your variables when you need to use them.
You say while (getline(s, input, ' ')) { //gets a string from the stream up the next comma but then you give the third argument ' '(a space). This should be a comma, I guess?
Fixed code:
cout << "File found" << endl;
while (getline(InFile, line)) {
cout << line << endl;
stringstream s(line); // create the string stream and init with line
while (getline(s, input, ',')) { //gets a string from the stream up the next comma
field++;
cout << " field" << field << " is " << input << endl;
}
cout << "DONE" << endl;
}
}

How to edit the specific line in a text file?

How should I edit the specific line in a text file? And how should I avoid overwriting issue. ( How do I keep the record I had added before instead of replacing them by the new records?)
I tried to use line.replace but it says " No matching member function for call to replace ".
else if(choice == 4){
// count++;
string edit;
string newdate;
double newincome;
double newoutcome;
double EditTodayBalance = 0;
string emptySpace = " ";
// string sentence;
cout << " There are " << count << " record(s) in the file " << endl;
cout << " Please enter the date to edit " << endl;
cin >> edit;
size_t pos;
ifstream Record("BankRecord.txt");
if (Record.is_open()) {
while (getline(Record, line)) {
pos = line.find(edit);
if (pos != string::npos) // string::npos is returned if
string is not found
{
cout << line << endl;
cout << " Enter what you want to replace " << endl;
cout << " Please enter the new date you want to put " << endl;
cin >> newdate;
cout << " Please enter the new income you want to put " << endl;
cin >> newincome;
cout << " Please enter the new outcome you want to put " << endl;
cin >> newoutcome;
cout << " Your new Record is " << endl;
cout << count << emptySpace << newdate << emptySpace << newincome << emptySpace << newoutcome << endl;
//line.replace()
}
}
}
EditTodayBalance = newincome - newoutcome;
cout << " Today's balance is " << EditTodayBalance << endl;
cout << " Please reenter your choice " << endl;
cin >> choice;
}
I expect if the old line is " 1 2/2/2019 32 21 " and I input the new line to be " 1 2/3/2019 22 11 ". Then when I open the file the record will be the new one.
I'm afraid you will have to re-write the entire file. Read the content of the file line by line, store it in memory (maybe a vector of strings). Now do your editing on the specified line in that vector. When the operation is complete, dump the entire content of vector in another file. You may later replace the original file.

Issue with saving an edited infile to an outfile in c++

Im having an issue with the last section of coding on here. The // Copy files from infile to outfile. The program transfers my infile which is simply a an 8 digit number , 20392207,splits it up into individual digits using the .at method; and is supposed to save that output to an outfile. I cant figure out how to save the output to the outfile. Any advice?
infile looks as follows
20392207
program output looks like this
The input number :20392207
The number 1:2
The number 2:0
The number 3:3
The number 4:9
The number 5:2
The number 6:2
The number 7:0
The number 8:7
outfile is supposed to look like the program out put, but instead just looks like an exact copy of the infile.
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<string>
#include<cmath>
using namespace std;
int main()
{
string ifilename, ofilename, line, line2;
ifstream inFile, checkOutFile;
ofstream outFile;
char response;
int i;
// Input file
cout << "Please enter the name of the file you wish to open : ";
cin >> ifilename;
inFile.open(ifilename.c_str());
if (inFile.fail())
{
cout << "The file " << ifilename << " was not successfully opened." << endl;
cout << "Please check the path and name of the file. " << endl;
exit(1);
}
else
{
cout << "The file is successfully opened." << endl;
}
// Output file
cout << "Please enter the name of the file you wish to write : ";
cin >> ofilename;
checkOutFile.open(ofilename.c_str());
if (!checkOutFile.fail())
{
cout << "A file " << ofilename << " exists.\nDo you want to continue and overwrite it? (y/n) : ";
cin >> response;
if (tolower(response) == 'n')
{
cout << "The existing file will not be overwritten. " << endl;
exit(1);
}
}
outFile.open(ofilename.c_str());
if (outFile.fail())
{
cout << "The file " << ofilename << " was not successfully opened." << endl;
cout << "Please check the path and name of the file. " << endl;
exit(1);
}
else
{
cout << "The file is successfully opened." << endl;
}
// Copy file contents from inFile to outFile
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
for (i = 0; i < 8; i++)
{
cout << "The number " << i + 1 << ":";
cout << line.at(i);
cout << endl;
}
outFile << line << endl;
}
// Close files
inFile.close();
outFile.close();
} // main
Here we can see that outFile is only written to outside of the while loop:
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
for (i = 0; i < 8; i++)
{
cout << "The number " << i + 1 << ":";
cout << line.at(i);
cout << endl;
}
}
outFile << line << endl;
It has no chance of containing the same output as the console
Solution: Write inside the loop the same stuff that was written to the console:
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
outFile << "The input number :" << line << endl;
blah blah blah
}
But this looks like crap and a function makes like a better solution by eliminating duplication and upping re-usability.
void output(std::ostream & out,
const std::string & line)
{
out << "The input number :" << line << endl;
for (int i = 0; i < 8; i++)
{
out << "The number " << i + 1 << ":";
out << line.at(i);
out << endl;
}
}
and called:
while (getline(inFile, line))
{
output(cout, line);
output(outFile, line);
}
You need to write to outFile inside the while(getline(inFile, line)) loop.
[edit] see user4581301's answer for a more thorough treatment.

ifstream still reading after eof

I am writing a program that is going to have to import data from a file into various containers. I have it importing everything properly, but it is continuing to read after what is supposed to be the eof. I have a feeling I am not properly telling the loop when to end, but the code is below for everyone to look at.
bool InitLoad(vector<string>&num, vector<string>&name, vector<double>&price, vector<char>&tax)
{
ifstream invFile;
int intTemp;
string strTemp;
double dubTemp;
char chTemp;
string fileLoc = "C:/Users/owner/Documents/Visual Studio 2010/Projects/CISS 350/Week 1 Grocery Register/Week 1 Grocery Register/Invent.dat";
//Open Invent.dat file. Location below is the location used on creators computer. Other may need to modify file location
invFile.open(fileLoc.c_str(), ios::in);
//If Invent.dat file fails to open display error message and return false
if(invFile.fail())
{
cout << "Could not open inventory file" << endl;
return false;
}
if(invFile)
{
//Read first line of the file
getline(invFile, strTemp, ' ');
while(invFile) //while invFile contains data display import the list
{
cout << strTemp << " ";
num.push_back(strTemp);
getline(invFile, strTemp, ' ');
cout << strTemp << " ";
name.push_back(strTemp);
getline(invFile, strTemp, ' ');
dubTemp = atof(strTemp.c_str());
cout << dubTemp << " ";
price.push_back(dubTemp);
invFile.get(chTemp);
cout << chTemp;
tax.push_back(chTemp);
getline(invFile, strTemp, ' ');
}
}
invFile.close();
cout << endl;
//Verify Proper input...REMOVE WHEN COMPLETE
cout << "Verifying input data correct..." << endl;
int vecSize = num.size();
cout << vecSize << endl;
for(int i = 0; i < vecSize; i++)
{
cout << num[i] << " " << name[i] << " " << price[i] << " " << tax[i] << endl;
}
}
Your check does not check eof flag
http://www.cplusplus.com/reference/ios/ios/operator_bool/
use invFile.eof() instead
And also eof flag would be setted after reading past EOF
PS: OMG!! do not use atof, just do invFile << dubTemp
Since your data is space separated you can uses formatted input instead of getline() on every string.
Something along the lines of this.
string lineTemp;
while(getline(invFile, lineTemp)) //while invFile contains data display import the list
{
string strTemp1, strTemp1, dubTemp, chTemp;
istringstream lstr(lineTemp);
if(lstr >> strTemp1 >> strTemp2 >> dubTemp >> chTemp) {
num.push_back(strTemp1);
name.push_back(strTemp2);
price.push_back(dubTemp);
tax.push_back(chTemp);
cout << strTemp1 << " "
<< strTemp2 << " "
<< dubTemp << " "
<< chTemp << endl;
}
else {
// Something is wrong with the line format.
}
}
This will read the data in a formated way and to the proper type. Plus you don't have to worry about empty lines or extra characters in lines.

Vector of Structs of Vector and String Not printing correctly

I am a beginning c++ student and am attempting to write a program that takes a word in a file and indexes it, listing each word only once and displaying the line numbers of every time that word appears. I have tried using a map but i found it impossible to get the line numbers for the words. Instead, I am using a vector of structs that has an integer vector and a string for each word. I am trying to read each word, place it into a stringstream, then output it into the string in the struct. Then I take the line number and push_back it into the vector in the struct. then I save everything to the vector of the struct and try to print out each word associated with the line number vector. I am getting nowhere and would like some help. Itd be much appreciated! Here is my source code:
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
struct words {
vector<int> lineNumbers;
string word;
};
int main() {
ifstream inFile, testStream;
ofstream outFile;
string temp, choice, inFileName, outFileName, word, trash, word2, tempString;
int idx = 0, count = 0, idxTwo = 0;
bool outputOpened = false;
//map <string,int> wordList;
/map <string,int>::iterator wordIt;
stringstream myStream(ios_base::in| ios_base::out);
vector<words> myIndex;
words data;
for (;;) {
cout << "Options: "<< endl << "1. Index" << endl << "2. Quit" << endl
<< "Please enter an option: ";
getline(cin, temp);
//cin >> temp;
//cin.ignore(8192, '\n');
choice.resize(temp.length());
transform(temp.begin(), temp.end(), choice.begin(), ::toupper);
if (choice.compare("INDEX") == 0 || choice.compare("1") == 0) {
do {
inFileName.clear();
cout << "Index Program" << endl
<< "==============" << endl << endl;
cout << "Input file name: ";
getline(cin, inFileName);
inFile.open(inFileName.c_str());
if(inFile.fail()) {
cout << "Can't open file" << endl;
if(inFile.bad()) {
cout << "Bad" << endl;
}
inFile.clear();
}
}
while (!inFile.is_open());
do {
cout << "Output file name: ";
getline( cin, outFileName);
testStream.clear();
testStream.open(outFileName.c_str());
if(testStream.good()) {
cout << "That file already exists, try again" << endl;
testStream.clear();
testStream.close();
}
else {
testStream.clear();
testStream.close();
outFile.open(outFileName.c_str());
if (outFile.good()) {
outputOpened = true;
}
}
}
while (!outputOpened);
while (getline(inFile, trash)){
count++;
myStream << trash;
//myStream >> tempString;
while(myStream >> data.word) {
data.lineNumbers.push_back(count);
myIndex.push_back(data);
}
}
for (idx = 0; idx < myIndex.size(); idx++) {
outFile << "Word: "<< " "<< myIndex[idx].word << ", ";
for (idxTwo = 0; idxTwo < myIndex[idx].lineNumbers.size(); idxTwo++) {
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo];
}
}
inFile.close();
outFile.close();
}
else if (choice.compare("QUIT") == 0 || choice.compare("2") == 0) {
return 0;
}
else {
cout << temp << " is an unrecognized option, please try again" << endl;
}
}
return 0;
}
Your problem seems to be that you are always appending each word to the vector<words>.
What you probably want, is a map<string, vector<int>>. Use .insert to insert words in to the set, if it already exists then just append the current line number to the value.
For this part of your program:
while (getline(inFile, trash)){
count++;
myStream << trash;
//myStream >> tempString;
while(myStream >> data.word) {
// 2.
// data.lineNumbers.clear();
data.lineNumbers.push_back(count);
myIndex.push_back(data);
}
// 1. add:
// myStream.clear();
}
You are using a global myStream. But the state of this myStream will be in a bad state after processing each line, as it ran out of data. The state mush be cleared for it to work again.
The data is also global, which make the line number for every word to be saved in data.lineNumber, not only the line number of the current word. You may want to clear it at each run.
Here are some issues:
Add myStream.clear(); after the while(myStream >> data.word) loop.
Add "\n" to the end of the following line to print on a new line:
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo]<<"\n";
Also, the following nested loop will not give you correct results. It will grow with line numbers and keep printing "Found on lines":
for (idx = 0; idx < myIndex.size(); idx++) {
outFile << "Word: "<< " "<< myIndex[idx].word << ", ";
for (idxTwo = 0; idxTwo < myIndex[idx].lineNumbers.size(); idxTwo++) {
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo]<<"\n";
}