C ++中的文件处理:更新一行

时间:2018-09-16 17:57:50

标签: c++ fstream file-handling

我正在编写图书馆管理程序。我有一个文件 Student.dat ,该文件有四列。最初,当没有书发行时,它看起来像这样。

     ---------------Students List ----------------
Roll No.                Name                    Book Issued        Issued Book No.
001                     Abhi                    0                  No
002                     Ashu                    0                  No

将书发行到'001'之后。

 ---------------Students List ----------------
Roll No.                Name                    Book Issued             Issued Book No.
001                     Abhi                    1                       1001
02                      Ashu                    0                       No

第二名学生的卷数变为'02'。

这是library.cpp中的完整发行功能

    void Library::book_issue()
    {
        //Some code
        fp.open("Students.dat", std::ios::in | std::ios::out);
        fp1.open("Books.dat", std::ios::in | std::ios::out);
//////////////////////////////////////////////////////////////////////
        int oldPos = fp.tellg();
        while (std::getline(fp, line) && !found_stu)
        {
            std::stringstream ss(line);
            ss >> roll_n >> s_name >> tkn >> issued_b_num;
               ////////////
            std::getline(ss, line);
            if (boost::iequals(roll_n, r_num))
            {
                found_stu = true;
                if (tkn == 0)
                {
                    std::cout << "Enter Book No. : ";
                    std::getline(std::cin, b_num);
                    while (fp1 >> book_n >> b_name >> a_name && !found_book)
                    {
                        if (boost::iequals(book_n, b_num))
                        {
                            Book::show_book(book_n, b_name, a_name);
                            found_book = true;
                            tkn = 1;
                            Student::reset_issued_book_num();
                            issued_b_num = book_n;
//////////////////////////////////////////////////////////////////
                            fp.seekg(oldPos);
                           fp << roll_n << " " << s_name << " " << tkn << " " << issued_b_num << '\n';
                            std::cout << "Book Issued Successfully\n";
                            break;
                        }
                    }
                    if (!found_book)
                    {
                        std::cerr << "Book does not exist\n";
                    }
                }
            }
        }
        if (!found_stu)
        {
            std::cout << "Student record does not exist\n";
        }
        fp.close();
        fp1.close();
    }

我想知道我是否正确使用了oldPos变量?

编辑: 将Issued Book No.的长度分配为书号的长度后,我得到了重复记录。

 ---------------Students List ----------------
Roll No.                Name                    Book Issued             Issued Book No.
001                     Abhi                    1                       1001
001                     Abhi                    1                       1001
002                     Ashu                    0                       No

1 个答案:

答案 0 :(得分:2)

问题是您覆盖了读取的文件。因此,如果一行变长,则您将覆盖下一行的字符。

002变成02而不是2时,我假设文件中的No后跟一个空格。因此,如果我习惯于以可见的方式显示LineFeed,即文件的以下内容:

...NO <LF>002...

将被以下内容覆盖:

...1001<LF>02...
          ^         (end of the write, remaining chars unchanged)  

因此,三个字符No100覆盖,LineFeed被1覆盖,而0被新的LineFeed覆盖。

如果要像在此处尝试一样就地编写,则必须确保在任何情况下每行的大小均保持固定。因此,“ No”后应跟与书号长度匹配的空格数。

其他备注

这不是导致错误的原因,但是tellg()返回std::streampos,它可能比int大得多。因此,我建议您选择:

auto oldPos = fp.tellg();   // here you're sure it's the right type

还要注意,tellg() / seekg()用于输入流,tellp() / seekp()用于输出流。幸运的是,对于双向文件流,只有一个位置可以读写。但是对于其他类型的双向字符串,则无法保证(请参见this question)。

最后,如果重新定位的目标是覆盖最后一行,请阅读(发现)您应不时对其进行更新。