C++:从二进制文件读取输入时出现问题
C++: Problems reading input from a binary file
我在 AccountManagement.cpp 中有一个 class AccountManagement。我在 Account.cpp 中还有一个名为 Account 的 class。我有一个模板,它使用 OdereList class 对列表中的给定数据进行排序,它也有自己的迭代器。 AccountManagement class 在二进制文件中输出帐户列表,如下所示:
void AccountManagement::saveData(const char * file) //saves data in the specified binary file
{
ofstream out(file, ios::out | ios::binary);
if(!out)
{
cerr<<"Problem opening output file!"<<endl;
}
OrderedList<Account>::iterator it = this->account_manager.begin();
for(int i = 0; i < this->total_accounts; i++)
{
Account temp = *it;
out.write((char*)&temp, sizeof(Account));
it++;
}
out.close();
}
我在 AccountManagement class 中定义了以下函数,它从二进制文件中读取所有数据并将其输出。这个功能工作得很好。它显示在这里:
void AccountManagement::output()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
但是,当我在另一个文件中使用这个相同的函数(具有不同的名称)时,该文件也有 Account.h 头文件以及从同一个 "account.dat" 文件中检索数据时它给我分段错误.可能是什么问题呢?以下是函数:
void loadData()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
帐户的 class 声明:
class Account
{
friend ostream& operator<<(ostream&,const Account&); //overloading << operator
friend istream& operator>>(istream&,Account&); //overloading >> operator
public:
void operator=(const Account&); //overloading = operator
bool operator<=(const Account&); //overloading <= operator
bool operator<(const Account&); //overloading < operator
private:
string number; //Account Number
char name[100]; //Account holder's name
char sex; //M or F indicating the gender of account holder
MYLIB::Date dob; //date of birth of account holder
char address[100]; //address of account holder
char balance[20]; //balance of account holder
};
我不知道 MYLIB::Date
class,但是你有一个 std::string
对象就足够了。
std::string
对象动态 分配内存以适应它包含的字符串。堆上分配的内存仅供当前进程使用,您不能保存指针(位于 std::string
class 内)并从其他进程加载它并希望它有效该指针的内存。
如果您在一个进程中保存指向动态分配内存的指针,并从另一个进程加载和使用它,那么您将有未定义的行为。
您需要 serialize 字符串才能保存它。也可能是 MYLIB::Data
对象。
免责声明:它将在具有单一统一地址映射的小型嵌入式系统上工作,不幸的是所有面向用户的操作系统(如Windows、OSX 和 Linux) 在进程之间有独立的地址空间和隔离墙。
你的函数 AccountManagement::output()
给人的印象是它工作完美,如果你保存对象并在同一个对象中再次加载它 and 前提是字符串没有改变同时。
怎么了?
一旦您的对象不再是 POD 对象(即它包含使用指针或使用虚函数等的数据),您就不能仅通过将其内存写入磁盘。
在您的情况下,第二个函数因此失败。第一个功能只给人一种它有效的印象。该字符串是一个复杂的对象,它在某处存储指向动态分配内存的指针。如果您写入对象并像您一样读回它,而不更改对象,则只需重新读取内存中的值。读取的隐藏指针的值与读取前完全相同。这是一个非常幸运的情况。但在大多数情况下它会失败。
如何解决?
要保存您的对象,您应该将其序列化:write/reade 使用适当的函数将每个组件分别保存到文件中。
最简单的方法是使用一些现有的序列化库,例如boost serialization。
我在 AccountManagement.cpp 中有一个 class AccountManagement。我在 Account.cpp 中还有一个名为 Account 的 class。我有一个模板,它使用 OdereList class 对列表中的给定数据进行排序,它也有自己的迭代器。 AccountManagement class 在二进制文件中输出帐户列表,如下所示:
void AccountManagement::saveData(const char * file) //saves data in the specified binary file
{
ofstream out(file, ios::out | ios::binary);
if(!out)
{
cerr<<"Problem opening output file!"<<endl;
}
OrderedList<Account>::iterator it = this->account_manager.begin();
for(int i = 0; i < this->total_accounts; i++)
{
Account temp = *it;
out.write((char*)&temp, sizeof(Account));
it++;
}
out.close();
}
我在 AccountManagement class 中定义了以下函数,它从二进制文件中读取所有数据并将其输出。这个功能工作得很好。它显示在这里:
void AccountManagement::output()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
但是,当我在另一个文件中使用这个相同的函数(具有不同的名称)时,该文件也有 Account.h 头文件以及从同一个 "account.dat" 文件中检索数据时它给我分段错误.可能是什么问题呢?以下是函数:
void loadData()
{
ifstream in("accounts.dat", ios::in | ios::binary);
if(!in)
{
cerr<<"File doesn't exist!"<<endl;
exit(1);
}
Account acc;
while(in.read((char*)&acc, sizeof(Account)))
{
cout<<acc;
}
in.close();
}
帐户的 class 声明:
class Account
{
friend ostream& operator<<(ostream&,const Account&); //overloading << operator
friend istream& operator>>(istream&,Account&); //overloading >> operator
public:
void operator=(const Account&); //overloading = operator
bool operator<=(const Account&); //overloading <= operator
bool operator<(const Account&); //overloading < operator
private:
string number; //Account Number
char name[100]; //Account holder's name
char sex; //M or F indicating the gender of account holder
MYLIB::Date dob; //date of birth of account holder
char address[100]; //address of account holder
char balance[20]; //balance of account holder
};
我不知道 MYLIB::Date
class,但是你有一个 std::string
对象就足够了。
std::string
对象动态 分配内存以适应它包含的字符串。堆上分配的内存仅供当前进程使用,您不能保存指针(位于 std::string
class 内)并从其他进程加载它并希望它有效该指针的内存。
如果您在一个进程中保存指向动态分配内存的指针,并从另一个进程加载和使用它,那么您将有未定义的行为。
您需要 serialize 字符串才能保存它。也可能是 MYLIB::Data
对象。
免责声明:它将在具有单一统一地址映射的小型嵌入式系统上工作,不幸的是所有面向用户的操作系统(如Windows、OSX 和 Linux) 在进程之间有独立的地址空间和隔离墙。
你的函数 AccountManagement::output()
给人的印象是它工作完美,如果你保存对象并在同一个对象中再次加载它 and 前提是字符串没有改变同时。
怎么了?
一旦您的对象不再是 POD 对象(即它包含使用指针或使用虚函数等的数据),您就不能仅通过将其内存写入磁盘。
在您的情况下,第二个函数因此失败。第一个功能只给人一种它有效的印象。该字符串是一个复杂的对象,它在某处存储指向动态分配内存的指针。如果您写入对象并像您一样读回它,而不更改对象,则只需重新读取内存中的值。读取的隐藏指针的值与读取前完全相同。这是一个非常幸运的情况。但在大多数情况下它会失败。
如何解决?
要保存您的对象,您应该将其序列化:write/reade 使用适当的函数将每个组件分别保存到文件中。
最简单的方法是使用一些现有的序列化库,例如boost serialization。