【问题标题】:Problem in reading data of object from file in c++ [duplicate]在c ++中从文件中读取对象数据的问题[重复]
【发布时间】:2020-04-13 17:49:08
【问题描述】:
#include <iostream>
#include<fstream>
#include<string>
using namespace std;

class student{

private:
    string name;
    long  int rollNo;
public:
     static int noOfStudent;

    void getData(){
     cout<<"Enter name:";
     getline(cin,name);
     cout<<"Enter Roll No:";
     cin>>rollNo;
    }
    void storeInFile(){

    ofstream myfile;
    myfile.open("studentDataBase.txt",ios::app|ios::binary);
    if(myfile.fail())
        exit(-1);
    myfile.write((char*)this,sizeof(*this));
    myfile.close();
    }
    void  printData(){

    ifstream myfile;
    myfile.open("studentDataBase.txt",ios::binary);
    if(myfile.fail())
        exit(-1);
    myfile.read((char *)this,sizeof(*this));
    while(!myfile.eof()){
    cout<<this->name<<" "<<this->rollNo<<"\n";
    myfile.read((char *)this,sizeof(*this));
    }
  myfile.close();
    }
};
int student::noOfStudent;
int main()
{
   student st[100];
   st[0].getData();
   st[0].storeInFile();
   st[0].printData();
}

这是用于在文件中存储学生姓名和卷号并从文件中读取以打印学生详细信息的代码。 但是在从文件中读取数据并打印时出现问题。当我运行这个程序时, 并输入学生的详细信息,然后调用 printData() 函数,则该程序可以完美运行。 但是当我再次运行该程序并尝试仅调用 printData() 函数时,在输出中会显示一些垃圾值。我不明白为什么会这样? (很抱歉代码太长了)

【问题讨论】:

  • 您根本无法以这种方式阅读std::stringmyfile.read((char *)this,sizeof(*this)); 绝对是一个错误。 std::string 不是 POD 类型,它具有在恢复时无效的内部指针。注意 sizeof() 是一个编译时间常数。
  • 问题在于myfile.write 正在写入std::string 对象,而不是文本。因此,您可以将 std::string 对象中的所有变量和开销写入文件。此外,如果std::string 包含指针,则指针不会很好地转换回来,因为操作系统可以在每次运行程序时移动您的程序及其内存分配。
  • 由于文本是一个 可变长度 字段,因此您必须先写长度,然后是文本,或者写文本后跟终止字符,例如nul, '\0'.
  • 我建议以文本格式写出,首先是卷号、空格、学生姓名,然后是换行符。对于这个小项目,你不需要写二进制; text 就可以了(文件不大,所以不值得节省)。
  • @AmitNandal 但是你不能在 C++ 中存储对象,一般情况下也不能。您可以存储 一些 对象(所谓的 POD 类型),但您的不是其中之一。

标签: c++ file-handling


【解决方案1】:

我不建议这样做:

myfile.write((char*)this,sizeof(*this));

因为您的 student 课程不是 PODHere 解释了为什么使用 POD 可能会起作用。

您正在将程序内存空间中的(在您的情况下为堆栈分配的)内存写入文件。稍后再读回来是未定义的行为。如果您想将student 类保存到文件(即序列化您的student 类),请写入相应的数据,例如“name”和“rollNo”,例如:myfile &lt;&lt; name; in ASCII 模式,或myfile.write(name.c_str(), name.size()); 二进制模式。或者更好的是,使用一些好的序列化工具。我可以推荐boost serialization

【讨论】:

  • 永远不要做那种事:这太强了。在某些情况下可以毫无问题地使用ofstream::writeifstream::read,而在某些情况下则无法使用它们。对此的解释将为您的答案增加巨大的价值。
  • 你说得对,我解释了一下。
【解决方案2】:

我建议以空格分隔的文本编写您的数据:

myFile << rollNo << " " << name << "\n";

这将允许您像这样读回它:

myFile >> rollNo;
std::getline(myFile, name);

std::getline 用于帮助与每行一条记录同步,并允许学生姓名中有空格。

编辑 1:二进制书写
如果一定要用二进制方式写,我建议先写文本的长度,后跟文本:

myFile.write((char *) &rollno, sizeof(rollno));
unsigned int length = name.length();
myFile.write((char *) &length, sizeof(length));
myFile.write(name.c_str(), length);

【讨论】:

  • 感谢 Thomas 的回答,但我也想做一个函数,通过他们的 rollno 搜索学生。我认为这种方法很难搜索。如果我错了,请纠正我?
  • 您不想搜索文件。将对象读入内存,然后搜索内存。见std::vectorstd::map
  • 我还有一个疑问::> 假设我运行这个程序并将对象读入内存然后搜索内存。这很完美。但是当我关闭这个程序并再次运行它时,我可以'无法访问我之前创建的那些对象。然后我必须搜索整个文件。有什么想法解决这个问题吗?
  • 可能有一种解决方法,但根据您的需要更复杂。对于您的简单程序,根据您的程序需要,将文件中的数据读入内存。当您的程序退出时,容器中的对象将消失;这是发明文件的原因之一:在程序退出或关闭电源后存储数据。
  • 为了满足您的好奇心,您需要向操作系统询问“永久”内存区域(程序退出后保留的内存区域)。使用这块内存;您可能希望使用分配器来提供给std::vectorstd::map。因此,您需要在操作系统中搜索 API。并非所有操作系统都支持此功能。在程序开始时读取文件要简单得多。
猜你喜欢
  • 2021-03-11
  • 2019-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 2020-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多