Delete specific line from file

[亡魂溺海] 提交于 2021-02-16 18:26:32

问题


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?


回答1:


What's in countRowsOfDb()? If it opens the file and counts the lines in 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:

studentVector.push_back( Student( id, name, grade, points, type ) );

in the input loop. In all later loops, studentVector.size() gives the number of entries, or you can use the iterators.

Even better would be to use std::getline on the input, then initialize an std::istringstream to parse each line. This will catch input format errors much more reliably. Something like:

std::string line;
int lineNumber = 0;
while ( std::getline( inDb, line ) ) {
    ++ lineNumber;
    std::istringstream data( line );
    if ( data >> id >> name >> grade >> points >> type ) {
        studentVector.push_back( Student( id, name, grade, points, type ) );
    } else {
        std::cerr << "Format error in lne " << lineNumber << std::endl;
    }
}

Also, it is generally a better idea to write to separate file, then rename it after having verified that the write worked, i.e.:

std::ofstream outDb( "files/students.dat.new" );
//  Do output...
outDb.close();
if ( outDb ) {
    remove( "files/students.dat" );
    rename( "files/students.dat.new", "files/students.dat" );
} else {
    std::cerr << "Write error on output" << std::endl;
}

And of course, any write error should result in a return of EXIT_FAILURE from main. (This is one case where a global variable or a singleton is justified—keeping track of the return code.)




回答2:


I made it to work by adding a new function that replays the content so now the code is:

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;

    for(int i = 0; i < countRowsOfDb(); i++)
    {
        if(studentsArray[i]->id != term)
        {
            Student studentTemp(studentsArray[i]->id, studentsArray[i]->name, studentsArray[i]->grade, studentsArray[i]->points, studentsArray[i]->type);
            replaceRow(studentTemp);
        }
    }

    cout << "\nObject deleted!\n";
}

and the replace function is:

void replaceRow(Student student)
{
    ofstream outDb("files/students.dat", ios::out);
    if(!outDb)
    {
        cerr << "File could no be opened!\n";
    }

    outDb << student.getId() << ' ' << student.getName() << ' ' << student.getGrade()
          << ' ' << student.getPoints() << ' ' << student.getType() << endl;

    outDb.close();
}


来源:https://stackoverflow.com/questions/11014929/delete-specific-line-from-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!