【问题标题】:Getting wrong output using seekg and seekp使用 seekg 和 seekp 得到错误的输出
【发布时间】:2016-05-02 21:53:39
【问题描述】:

我创建了一个类Student
学生类:

class Student
{
    friend ostream& operator<<(ostream& os, const Student& s)
    {
        return os <<
            "Roll no.: " << s.roll_no << '\n' <<
            "Name: " << s.name << '\n' <<
            "Phone no.: " << s.phone_no << '\n' <<
            "Address: " << s.address << '\n';
    }
public:
    Student() = default;
    Student(int r, const char* n, int p_no, const char* a):
        roll_no(r), phone_no(p_no)
    {
        strcpy(name, n);
        strcpy(address, a);
    }
    int get_roll() const
    {
        return roll_no;
    }
private:
    int roll_no;
    char name[40 + 1];
    int phone_no;
    char address[100 + 1];
};

StudentList 类中,我将一些学生对象存储在二进制文件中。

class StudentList
{
public:
    StudentList(const string& fname):
        filename(fname)
    {
        make_index();
    }
    Student get_student(int roll)
    {
        fstream ifs(filename, ios::in | ios::binary);
        int pos = index[roll];
        ifs.seekg(pos * sizeof(Student));
        Student s;
        ifs.read(reinterpret_cast<char*>(&s), sizeof(s));
        return s;
    }
    void change_student(Student s)
    {
        fstream ofs(filename, ios::out | ios::binary);
        int pos = index[s.get_roll()];
        ofs.seekp(pos * sizeof(s));
        ofs.write(reinterpret_cast<const char*>(&s), sizeof(s));
    }
    void add_student(Student s)
    {
        fstream ofs(filename, ios::out | ios::binary | ios::app);
        ofs.write(reinterpret_cast<const char*>(&s), sizeof(s));
        int total_no = index.size() + 1;
        index[s.get_roll()] = total_no - 1;
    }
private:
    string filename;
    map<int, int> index;
    void make_index()
    {
        fstream ifs(filename, ios::in | ios::binary);
        int pos = 0;
        if (ifs.is_open()) {
            while (!ifs.eof()) {
                Student s;
                ifs.read(reinterpret_cast<char*>(&s), sizeof(s));
                index[s.get_roll()] = pos;
                pos++;
            }
        }
    }
};

但是,此代码给出了错误的输出。运行程序时二进制文件不存在。所以StudentList::make_index在构造函数中调用时会创建一个新文件。

int main()
{
    StudentList sl("student.dat");
    sl.add_student(Student(14, "V", 12, "14/14"));
    sl.add_student(Student(1, "A", 12, "13/13 Tollygunge"));
    cout << sl.get_student(14) << '\n';
    cout << sl.get_student(1) << '\n';
    sl.change_student(Student(1, "B", 12, "14/14, Bosepukur Road"));
    cout << sl.get_student(14) << '\n';
    cout << sl.get_student(1) << '\n';
    return 0;
}

输出:

Roll no.: 14
Name: V
Phone no.: 12
Address: 14/14

Roll no.: 1
Name: A
Phone no.: 12
Address: 13/13 Tollygunge

Roll no.: 0
Name: 
Phone no.: 0
Address: 

Roll no.: 1
Name: B
Phone no.: 12
Address: 14/14, Bosepukur Road

尝试用gdb调试,发现StudentList::change_student(Student)函数不能正常工作。在函数中,尽管使用 seekp 设置文件中第一个 Student 对象之后的写入位置(如 pos = 1),但第一个 Student 对象也以某种方式被修改。
编辑:
我想我找到了错误。更改StudentList::change_student(Student s)中的这一行:

fstream ofs(filename, ios::out | ios::binary);

到:

fstream ofs(filename, ios::out | ios::binary | ios::in);

给出正确的输出。
输出:

Roll no.: 14
Name: V
Phone no.: 12
Address: 14/14

Roll no.: 1
Name: A
Phone no.: 12
Address: 13/13 Tollygunge

Roll no.: 14
Name: V
Phone no.: 12
Address: 14/14

Roll no.: 1
Name: B
Phone no.: 12
Address: 14/14, Bosepukur Road

很可能正如 Aumnayan 所建议的那样,之前的打开模式是在 change_student 函数中擦除文件的内容。

【问题讨论】:

  • 使用调试器会比在 StackOverflow 上进行对话更快。如果你不知道如何使用调试器,这个程序是学习使用调试器的绝佳案例。
  • @ThomasMatthews:我尝试使用 gdb 进行调试,发现 Student::change_student 无法正常工作,但我找不到确切的错误。尽管在函数中使用了 seekp 来设置文件中第一个 Student 对象之后的写入位置(如 pos = 1),但第一个学生对象也以某种方式被修改了。
  • seekp 正在工作,但您只有 2 个Students。您假设学生卷 1 将存储在插槽 1,学生 14 将存储在插槽 14。您的学生按顺序存储,未排序。因为它们没有被索引,所以您必须进行全面扫描。当您尝试寻找一条不存在的记录时,它会返回一条空记录。
  • 您打算如何在一个名为“Peaches Honeyblossom Michelle Charlotte Angel Vanessa Geldof-Cohen”的学生的意见中幸存下来?愿她安息。

标签: c++ file fstream binaryfiles seek


【解决方案1】:

尝试在 change_student 方法中添加 ios::app 标志。我似乎要记住 ios::out 是破坏性的,这会让你得到一个传播了 student(1) 并且学生 14 设置为(大概)0 的文件。我已经有一段时间没有玩过这种类型的文件了。所以YMMV。

【讨论】:

    猜你喜欢
    • 2013-03-18
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    相关资源
    最近更新 更多