简体   繁体   English

C ++从/向二进制文件读取/写入类

[英]c++ Read/Write class from/to binary file

I need to write a class to a binary file, and then I need to read it back. 我需要将一个类写入二进制文件,然后再将其读回。

I have Triangle and BinaryFile classes, and some other classes. 我有TriangleBinaryFile类,以及其他一些类。 I am not sure if I am writing incorrectly or reading incorrectly. 我不确定我是写错还是阅读不正确。 An error occurs when reading. 读取时发生错误。 After debugging, I think that it gets inappropriate data for my private variables. 调试后,我认为它为我的私有变量获取了不合适的数据。 I will be very glad if someone can give me some advice on how to make it work properly. 如果有人能给我一些有关如何使其正常工作的建议,我将感到非常高兴。

I wasn't sure if I should paste the whole code or not, so I will give you a short snippet of code. 我不确定是否应该粘贴整个代码,所以我将为您提供一小段代码。 Just in case, here is a download link for my source code: 以防万一,这是我的源代码的下载链接:

https://my.pcloud.com/publink/show?code=XZJ7CYZbsLWLglqV5p83csijcEUTFqqpM3k https://my.pcloud.com/publink/show?code=XZJ7CYZbsLWLglqV5p83csijcEUTFqqpM3k

I am a newbie in programming and I don't speak English very well, so I apologize in advance for my mistakes. 我是编程新手,英语说得不太好,所以我为自己的错误事先表示歉意。

class Point
{
private:
    int x;
    int y;
};

class Figure
{
private:
    string name;
    string type;
};

class Triangle: public Figure
{
private:
    Point p1, p2, p3;
};

class BinaryFile
{
private:
    string FileName;
    fstream File;
public:
    //...
    void AddNewFigure(istream& stream)
    {       
        File.open(this->FileName, ios::binary | ios::app);
        if(!this->File)
        {
            cerr<<"File error <"<<this->FileName<<">\n";
            exit(1);
        }
        Triangle fig;
        fig.MakeNewFigure(stream);
        File.write((char*)&fig, sizeof(Triangle));
        File.close();
    }

    Triangle GetTriangle()
    {
        Triangle trig;
        Point p;
        string str(""); int x(0);
        File.open(this->FileName, ios::binary | ios::in);
        if(!this->File)
        {
            cerr<<"File error <"<<this->FileName<<">\n";
            exit(1);
        }
        File.read((char*)&trig, sizeof(Triangle));
        File.close();
        return trig;
    }
};

The answer depends on whether you are just doing this to learn how files work or whether saving to the file is just incidental and you don't care how it works. 答案取决于您是否只是为了了解文件的工作方式而做,还是保存到文件中只是偶然的事,而又不在乎文件的工作方式。

If you just want to get the stuff to save and restore and you don't care how it works then use a third party library. 如果您只想保存和还原内容,而又不关心它的工作方式,请使用第三方库。 There are many many of them. 有很多很多。

If you want to learn how to read and write things to files then you will need to make your own read and write functions. 如果您想学习如何对文件进行读写,那么您将需要使用自己的读写功能。 I have made a sample program that will explain how it works: 我制作了一个示例程序,将解释其工作方式:

#include <string>
#include <fstream>
#include <iostream>

class Point
{
private:
    int x;
    int y;
public:
    Point():x(0),y(0){}
    Point(int x,int y):x(x),y(y){}

    void write(std::ostream& f)
    {
        // We can just write out the bytes for x and y because
        // they are primitive types stored in the class
        f.write( (char*)&x, sizeof(x) );
        f.write( (char*)&y, sizeof(y) );
    }
    void read(std::istream& f)
    {
        // We can just read the bytes directly into x and y because
        // they are primitive types stored in the class
        f.read( (char*)&x, sizeof(x) );
        f.read( (char*)&y, sizeof(y) );
    }
};

class Figure
{
private:
    std::string name;
    std::string type;
public:
    Figure(){}
    Figure(std::string name,std::string type):name(name),type(type){}

    void write(std::ostream& f)
    {
        size_t size;

        // we need to store the data from the string along with the size
        // because to restore it we need to temporarily read it somewhere
        // before storing it in the std::string (istream::read() doesn't
        // read directly to std::string)

        size = name.size();
        f.write( (char*)&size, sizeof(size_t) );
        f.write( (char*)name.c_str(), size );

        size = type.size();
        f.write( (char*)&size, sizeof(size_t) );
        f.write( (char*)type.c_str(), size );
    }
    void read(std::istream& f)
    {
        size_t size;
        char *data;

        // when we read the string data we need somewhere to store it
        // because we std::string isn't a primitive type.  So we read
        // the size, allocate an array, read the data into the array,
        // load the std::string, and delete the array

        f.read( (char*)&size, sizeof(size) );
        data = new char[size+1];
        f.read( data, size );
        data[size]='\0';
        name = data;
        delete data;

        f.read( (char*)&size, sizeof(size) );
        data = new char[size+1];
        f.read( data, size );
        data[size]='\0';
        type = data;
        delete data;
    }
};

class Triangle: public Figure
{
private:
    Point p1, p2, p3;
public:
    Triangle(){}
    Triangle(Point x,Point y,Point z,Figure f):p1(x),p2(y),p3(z),Figure(f){}


    void write(std::ostream& f)
    {
        // First write the base class then write the members of this class
        Figure::write(f);
        p1.write(f);
        p2.write(f);
        p3.write(f);
    }
    void read(std::istream& f)
    {
        // First read the base class then read the members of this class
        Figure::read(f);
        p1.read(f);
        p2.read(f);
        p3.read(f);
    }
};

class BinaryFile
{
private:
    std::string FileName;
    std::fstream File;
public:
    BinaryFile(std::string FileName) : FileName(FileName) {};
    void WriteTriangle()
    {
        File.open(FileName, std::ios::binary | std::ios::out);
        if(!File)
        {
            std::cerr<<"File error <"<<FileName<<">\n";
            exit(1);
        }
        Triangle trig({1,2},{3,4},{5,6},{"name","type"}); // something new
        trig.write(File);
        File.close();
    }

    Triangle ReadTriangle()
    {
        File.open(FileName, std::ios::binary | std::ios::in);
        if(!File)
        {
            std::cerr<<"File error <"<<FileName<<">\n";
            exit(1);
        }
        Triangle trig; // default values
        trig.read(File);
        File.close();
        return trig;
    }
};

main()
{
    BinaryFile bin("file.bin");
    bin.WriteTriangle();
    Triangle trig = bin.ReadTriangle();
    // at this point trig has the values we stored
    return 0;
}

It's not easy to reproduce the error, due to your large source code and missing data file. 由于您的源代码很大且缺少数据文件,因此重现该错误并不容易。 But a quick inspection shows that you read and write the binary data using bloc operations: 但是快速检查显示您使用bloc操作读取和写入二进制数据:

    Triangle trig; 
    ...
    File.read((char*)&trig, sizeof(Triangle));

Unfortunately this kind of approach only works if the object you want to save/load is of a class that is trivially copyable , as the following code will demonstrate: 不幸的是,这种方法仅在要保存/加载的对象属于可微复制的类时才有效,如以下代码所示:

if (is_trivially_copyable<Triangle>::value) 
    cout << "Triangle is  trivially copyable" << endl; 
else cout << "Triangle is not trivially copyable" << endl; 

So you'll have to serialize the object content writing field by field instead of using a bloc operation. 因此,您必须逐字段序列化对象内容写入字段,而不是使用bloc操作。 This FAQ on serialization should help you to consider the alternatives. 序列化常见问题解答应帮助您考虑替代方案。

What you are looking for is to serialize your classes/data that should be saved to file. 您正在寻找的是序列化应该保存到文件中的类/数据。 There are several libraries that has been optimized regarding time and memory consumption for this. 有一些库已针对时间和内存消耗进行了优化。 Would you mind using a 3rd party library? 您介意使用第三方库吗?

If not, have a look at for example boost serialization , cereal or maybe even Google's ProtoBuf . 如果没有,请查看例如boost序列化谷类食品 ,甚至是Google的ProtoBuf I recon Cereal is a good start if you are using C++11. 如果您正在使用C ++ 11,我认为谷物是一个好的开始。

If you'd like to write your own serialization you'd have to consider that for every object that has a dynamic size (such as a string), you will also need to save the object's size to the file. 如果要编写自己的序列化,则必须考虑到对于每个具有动态大小(例如字符串)的对象,还需要将对象的大小保存到文件中。 For more info please have a look here: 有关更多信息,请在这里查看:

https://stackoverflow.com/a/11003590/5874704 https://stackoverflow.com/a/11003590/5874704

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM