I’m trying to delete a specific line by id from a file in C++ and here is my code:
void deleteRow()
{
ifstream inDb("files/students.dat", ios::in);
if(!inDb)
{
cerr << "File could no be opened!\n";
}
cout << countRowsOfDb() << " records." << endl;
Student *studentsArray[countRowsOfDb()];
int n = 0;
while(inDb >> id >> name >> grade >> points >> type)
{
studentsArray[n] = new Student(id, name, grade, points, type);
n++;
}
inDb.close();
for(int i = 0; i < countRowsOfDb(); i++)
{
cout << studentsArray[i]->id << " " << studentsArray[i]->name << " " << studentsArray[i]->grade << " "
<< studentsArray[i]->points << " " << studentsArray[i]->type << "\n";
}
cout << "\nWhich one you would like to delete? Enter an id: ";
string term;
cin >> term;
ofstream outDb("files/students.dat", ios::out);
if(!outDb)
{
cerr << "File could no be opened!\n";
}
for(int i = 0; i < countRowsOfDb(); i++)
{
if(studentsArray[i]->id != term)
{
outDb << studentsArray[i]->id << " " << studentsArray[i]->name << " " << studentsArray[i]->grade << " "
<< studentsArray[i]->points << " " << studentsArray[i]->type << "\n";
}
}
outDb.close();
cout << "\nObject deleted!\n";
}
I create a input file stream and then get all the rows, make it array of objects and show them on the screen then ask which one to delete by typing an id, and when I type the id, I’m trying to put all these elements of the array only without the element with same id, but it don’t works, after that there is nothing in the file. Any ideas?
What’s in
countRowsOfDb()? If it opens the file and counts the linesin it (and I don’t know what else it could do), then it’s not going to
find a lot in the final loop, since the creation of the ostream with the
same name will have emptied the file.
More generally, this is a very inefficient way of doing things (and
could easily fail if there were an error in the format of the file).
The best way to handle this is to use an
std::vector<Student>, with:in the input loop. In all later loops,
studentVector.size()gives thenumber of entries, or you can use the iterators.
Even better would be to use
std::getlineon theinput, then initialize an
std::istringstreamto parse each line. Thiswill catch input format errors much more reliably. Something like:
Also, it is generally a better idea to write to separate file, then
rename it after having verified that the write worked, i.e.:
And of course, any write error should result in a return of
EXIT_FAILUREfrommain. (This is one case where a global variableor a singleton is justified—keeping track of the return code.)