簡體   English   中英

C ++從/向二進制文件讀取/寫入類

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

我需要將一個類寫入二進制文件,然后再將其讀回。

我有TriangleBinaryFile類,以及其他一些類。 我不確定我是寫錯還是閱讀不正確。 讀取時發生錯誤。 調試后,我認為它為我的私有變量獲取了不合適的數據。 如果有人能給我一些有關如何使其正常工作的建議,我將感到非常高興。

我不確定是否應該粘貼整個代碼,所以我將為您提供一小段代碼。 以防萬一,這是我的源代碼的下載鏈接:

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

我是編程新手,英語說得不太好,所以我為自己的錯誤事先表示歉意。

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;
    }
};

答案取決於您是否只是為了了解文件的工作方式而做,還是保存到文件中只是偶然的事,而又不在乎文件的工作方式。

如果您只想保存和還原內容,而又不關心它的工作方式,請使用第三方庫。 有很多很多。

如果您想學習如何對文件進行讀寫,那么您將需要使用自己的讀寫功能。 我制作了一個示例程序,將解釋其工作方式:

#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;
}

由於您的源代碼很大且缺少數據文件,因此重現該錯誤並不容易。 但是快速檢查顯示您使用bloc操作讀取和寫入二進制數據:

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

不幸的是,這種方法僅在要保存/加載的對象屬於可微復制的類時才有效,如以下代碼所示:

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

因此,您必須逐字段序列化對象內容寫入字段,而不是使用bloc操作。 序列化常見問題解答應幫助您考慮替代方案。

您正在尋找的是序列化應該保存到文件中的類/數據。 有一些庫已針對時間和內存消耗進行了優化。 您介意使用第三方庫嗎?

如果沒有,請查看例如boost序列化谷類食品 ,甚至是Google的ProtoBuf 如果您正在使用C ++ 11,我認為谷物是一個好的開始。

如果要編寫自己的序列化,則必須考慮到對於每個具有動態大小(例如字符串)的對象,還需要將對象的大小保存到文件中。 有關更多信息,請在這里查看:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM