使用 seekg 和 seekp 得到错误的输出
Getting wrong output using seekg and seekp
我创建了一个 class Student
.
学生 class:
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 中,我将一些学生对象存储在二进制文件中。
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 函数中删除文件的内容。
尝试在 change_student 方法中添加 ios::app 标志。我记得 ios::out 是破坏性的,这会给你留下一个传播了学生(1)并且学生 14 设置为(大概)0 的文件。我已经有一段时间没有玩过这种类型的文件了 io tho ,所以 YMMV。
我创建了一个 class Student
.
学生 class:
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 中,我将一些学生对象存储在二进制文件中。
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 函数中删除文件的内容。
尝试在 change_student 方法中添加 ios::app 标志。我记得 ios::out 是破坏性的,这会给你留下一个传播了学生(1)并且学生 14 设置为(大概)0 的文件。我已经有一段时间没有玩过这种类型的文件了 io tho ,所以 YMMV。