从文件中删除特定行

时间:2012-06-13 12:35:12

标签: c++ line fstream

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

2 个答案:

答案 0 :(得分: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_FAILURE的{​​{1}}。 (这是全局变量的一种情况 或单身是合理的 - 跟踪返回代码。)

答案 1 :(得分: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();
}