【问题标题】:How to read from file and store in array of objects in c++如何从文件中读取并存储在c ++中的对象数组中
【发布时间】:2020-11-26 16:05:59
【问题描述】:

我正在学习 c++,但在文件处理方面遇到了麻烦。我正在编写一个代码作为作业,我必须将对象写入文件,然后一次将这些对象作为数组从文件中读取。这是我的代码:

#include <iostream>
#include <fstream>

using namespace std;

class Records{
    char* name;
    int roll;
public:
    Records()
    {
        name = new char[20];
    }
    void setData()
    {
        cout<<"Enter name: "<<endl;
        cin>>name;
        cout<<"Enter roll"<<endl;
        cin>>roll;
    }
    char* getname()
    {
        return name;
    }
    int getRoll()
    {
        return roll;
    }
    void operator = (Records& no)
    {
        name = no.name;
        roll = no.roll;
    }
};

int main()
{
    int i =0 ;
    Records rec;
    rec.setData();
    Records::increase();
    ofstream fout;
    fout.open("file.txt", ios::app);
    fout.write((char*)&rec, sizeof(rec));
    fout.close();

    Records* results = new Records[20];
    Records rec1;
    ifstream fin;
    fin.open("file.txt", ios::in);
    while(!fin.eof())
    {
        fin.read((char*)&rec1, sizeof(rec1));
        results[i] = rec1;
        i++;
    }
    fin.close();
    cout<<results[0].getRoll();
    return 0;
}

所以基本上,我创建了一个 Records 类并将其对象存储在一个文件中。这很好,但我在从文件中获取数据时遇到了问题。它没有显示任何内容或有时显示垃圾值。任何人有更好的想法请帮助我。 提前致谢!

【问题讨论】:

  • 你必须使用原始指针吗?为什么不使用std::string?由于char* name,您的类非常不安全,并且它泄漏内存,因为您没有delete[] 指针。阅读rule of 3/5/0。另请阅读:Why is iostream::eof() inside a loop condition (i.e. while (!stream.eof())) considered wrong?
  • 您不能将指针存储在文件中并在以后使用它们。你需要某种序列化。
  • 你做的水平比较低,没必要那么低。如果您只想将字符串和每行的数字写入文本文件,使用 ofstreams operator&lt;&lt; 会简单得多

标签: c++ file-handling


【解决方案1】:

首先,您必须以二进制模式打开文件进行读写。

 std::ofstream fou("out_filename",std::ofstream::binary);
 std::ifstream fin("in_filename", std::ifstream::binary);

其次,你分配 operator=() 是有问题的。它使用相同的地址分配两条记录。因此在读取过程中,result[i]中的20个元素都共享rec1::name的地址。您必须通过复制名称的内容来更正 operator=()。

这不好。

void operator = (Records& no)
{
    name = no.name;
    roll = no.roll;
}

改写如下:

编辑:因为您的对象最初都分配有其内存。不需要新的分配。

Records& Records::operator=(const Records& no)
{
   // this->name = new char [20]; 
    std::copy_n(no.name, 20, this->name); // include <algorithm>
    roll = no.roll;
    return *this; // return current object for another =.
}

最后,添加一个析构函数

Records::~Records() {
delete [] this->name; }

祝你好运!

【讨论】:

    【解决方案2】:

    在修复了一些其他错误后,我发布了这个最终版本供您参考。请注意,此项目不能对字段“名称”使用动态分配。使用动态分配,“name”的20字节不计入类Records的大小,指针本身不可传递。它会导致“名称”字段中的读/写错误。

    #include <iostream>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    
    class Records{
        char name[20];
        int roll;
    public:
        Records()
        {
          //  name = new char[20];
        }
        void setData()
        {
            cout<<"Enter name: "<<endl;
            cin>>name;
            cout<<"Enter roll"<<endl;
            cin>>roll;
        }
        const char* getname() const
        {
            return name;
        }
        int getRoll() const
        {
            return roll;
        }
        Records& operator = (const Records& no)
        {
            std::copy_n(no.name, 20, this->name);
            roll = no.roll;
            return *this;
        }
    };
    int main()
    {
        int i =0, c ;
        std::string a;
        Records rec;
        ofstream fout;
        fout.open("file.txt", std::ofstream::binary);
        c = 0;
        while (1)
        {
           std::cout << "Input record [" << c << "] ? (y/n) ";
           std::cin >> a;
           if (a[0]=='y' || a[0]=='Y')
            {
              rec.setData();
              fout.write((char*)&rec, sizeof(rec));
              ++c;
            }
            else break;
        }
        fout.close();
    // output 
        Records* results = new Records[20];
        Records rec1;
        ifstream fin;
        fin.open("file.txt", std::ifstream::binary);
        while(!fin.eof())
        {
           fin.read((char*)&rec1, sizeof(rec1));
           results[i] = rec1;
           i++;
        }
       fin.close();
       // eidt to print all records
       for (int j=0; j<(i-1); j++)
        {  std::cout << "record # = " << j << std::endl;
           std::cout << "   name = " << results[j].name;
           std::cout << "   roll = " << results[j].roll << std::endl;
        }
    
       return 0;
    }
    

    试运行

    $ ./a.exe
    Input record [0] ? (y/n) y
    Enter name:
    aaaa
    Enter roll
    1234
    Input record [1] ? (y/n) y
    Enter name:
    bbbb
    Enter roll
    2345
    Input record [2] ? (y/n) y
    Enter name:
    cccc
    Enter roll
    3456
    Input record [3] ? (y/n) n
    1234
    

    【讨论】:

    • 谢谢先生!但我还有一个问题,如何一次显示所有记录,因为我们的数组没有多大?
    • @SachinBhusal 在读取过程中,变量 i 是获取的记录数。但是由于while(文件结束条件),有一条额外的记录与最后一条的数​​据重复。请查看我编辑的部分以获取演示。
    • @SachinBhusal 是的。运行后,您可以进入目录并将file.txt更改为另一个名称,例如文件保存.txt。然后重写你的程序,备注第一部分(输入部分),直接进入第二部分:打开filesave.txt并从中读取。
    • 当我从文件中读取时,它以二进制形式显示,就像它保存在文件中一样。我的意思是它没有以正确的“英文”可读文本显示。为什么?
    • @SachinBhusal 当然。您以二进制形式保存它,并且还必须以二进制形式打开它。您无法在记事本中打开此类文件,或将其作为文本文件读取。 >>> 您可以打开file.txt 追加模式,允许您继续将新记录写入文件末尾。
    猜你喜欢
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    相关资源
    最近更新 更多