3

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

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 的元素,但它不起作用,之后文件中没有任何内容。有任何想法吗?

4

2 回答 2

2

里面有什么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_FAILUREfrom的返回main。(这是全局变量或单例合理的一种情况——跟踪返回码。)

于 2012-06-13T13:00:21.377 回答
0

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

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();
}
于 2012-06-13T12:58:28.027 回答