从文件中删除特定行

Delete specific line from file

本文关键字:删除 文件      更新时间:2023-10-16

我正在尝试从C++文件中按 id 删除特定行,这是我的代码:

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";
}

我创建一个输入文件流,然后获取所有行,使其成为对象数组并在屏幕上显示它们,然后通过键入 id 询问要删除哪一个,当我键入 id 时,我尝试仅放置数组的所有这些元素,而没有具有相同 id 的元素, 但它不起作用,之后文件中没有任何内容。有什么想法吗?

countRowsOfDb()里有什么? 如果它打开文件并计算行数在其中(我不知道它还能做什么),那么它就不会在最后一个循环中找到很多,因为创建了 ostream 与相同的名称将清空该文件。

更一般地说,这是一种非常低效的做事方式(并且如果文件格式有错误,很容易失败)。处理此问题的最佳方法是使用 std::vector<Student> ,具有:

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

在输入循环中。 在所有后面的循环中,studentVector.size()给出了条目数,或者您可以使用迭代器。

更好的是使用 std::getline输入,然后初始化一个std::istringstream来解析每一行。 这将更可靠地捕获输入格式错误。 像这样:

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;
    }
}

此外,通常更好的主意是写入单独的文件,然后在验证写入有效重命名它,即:

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;
}

当然,任何写入错误都会导致返回 EXIT_FAILURE来自main. (这是全局变量的一种情况或者单例是合理的 - 跟踪返回代码。

我通过添加一个重播内容的新函数来使其工作,因此现在的代码是:

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";
}

替换函数为:

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();
}