将向量加载并保存到文件 [英] Loading and Saving vectors to a file

查看:88
本文介绍了将向量加载并保存到文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C ++ Builder,并且有一个约会对象的向量数组。



我想保存



当前,我在二进制文件中使用ifstream和ofstream。我有一个标头,其中包含将与数据一起保存的向量的大小,以便在加载时知道其大小。



序列化是一种更好的方法吗?



如果是,我是否需要使用boost库或其他方式?



这是我当前的代码:

 班级任命
{
public:
约会();
约会(TDateTime aDate,TDateTime aReminderDateTime,字符串aType,
字符串aLocation,字符串aComments,布尔aIsImportant)
{
appDateTime = aDate;
appReminderDateTime = aReminderDateTime;
appType = aType;
appLocation = aLocation;
appComments = aComments;
appIsImportant =重要
}
void setAppDateTime(TDateTime aDateTime)
{
appDateTime = aDateTime;
}
void setappReminderDateTime(TDateTime aReminderDateTime)
{
appReminderDateTime = aReminderDateTime;
}
/ *
void printAppointmentDetails()
{
cout<< 约会日期:<< appDateTime<<恩德尔
cout<< 约会提醒日期:<< appReminderDateTime<<恩德尔
cout<< 约会类型:<< appType<<恩德尔
cout<< 约会位置:<< appLocation<<恩德尔
cout<< 约会评论:<< appComments<<恩德尔
if(appIsImportant)
{
cout<< 约会很重要:<< 是<<恩德尔
}否则{
cout<< 约会很重要:<< 否<<恩德尔
}
}

* /
void setType(string aType)
{
appType = aType;
}
void setLocation(string aLocation)
{
appLocation = aLocation;
}
void setComments(string aComments)
{
appComments = aComments;
}
void setIsImportant(bool aIsImportant)
{
appIsImportant = aIsImportant;
}
TDateTime getAppDateTime()
{
return appDateTime;
}
TDateTime getAppReminderDateTime()
{
return appReminderDateTime;
}
字符串getType()
{
return appType;
}
字符串getLocation()
{
return appLocation;
}
字符串getComments()
{
return appComments;
}
bool getIsImportant()
{
return appIsImportant;
}
private:
// appointment();
TDateTime appDateTime;
TDateTime appReminderDateTime;
字符串appType;
字符串appLocation;
字符串appComments;
bool应用重要;
//个人所有者;
};

类日历
{
public:
calendar()
{
// loadFromFile();
//加载人员
// calculateimportantAppointments
}
〜calendar()
{
saveToFile();
}
//添加人员
//编辑人员
//删除人员
void createAppointment(TDateTime aDate,TDateTime aReminderDateTime,string aType,
string aLocation,string aComments,bool aImportant)
{
约会newAppointment(aDate,aReminderDateTime,aType,
aLocation,aComments,aIsImportant);
约会.push_back(newAppointment);
}
/ *
void printAllAppointmentDetails()
{
for(int i = 0; i<约会.size(); i ++)
{
约会[i] .printAppointmentDetails();
}
}
void computeImportantAppointments()
{

}
int getNumberOfImportantAppointments()
{
int intImportantAppointmentCount = 0;
for(int i = 0; i< ations.size(); i ++)
{
if(appointments [i] .getIsImportant())
intImportantAppointmentCount + = 1 ;
}
return intImportantAppointmentCount;
}

约会[] getImportantAppointments()
{

}
约会[] getAllAppointments()
{

}
* /
void loadFromFile()
{
ifstream iStream( file.ext,ios :: binary);
if(!iStream)
{
cout<< 无文件;
} else {
fileHeader_t fHeader;
iStream.read((char *)& fHeader,sizeof(fileHeader_t));
if(fHeader.magicNumber = 0xDEADBEAF)
{
约会.resize(fHeader.appointmentCount);
iStream.read((char *)& appointments [0],fHeader.appointmentCount * sizeof(appointment));
}
}
}
void saveToFile()
{
ofstream oStream( file.ext,ios :: binary);
fileHeader_t fHeader;
fHeader.magicNumber = 0xDEADBEAF;
fHeader.appointmentCount =约会.size();
oStream.write((char *)& fHeader,sizeof(fileHeader_t));
oStream.write((char *)& appointments [0],sizeof(appointment)*约会.size());
}
// vector< appointment>约会;
私人:
vector< pointment>约会;
string calCurrentDate;
字符串calCurrentTime;
typedef struct fileHeader_s
{
DWORD magicNumber;
size_t约会计数;
} fileHeader_t;
};

调用loadFromFile()方法时出现以下错误。


[BCC32警告] File1.cpp(185):W8060可能是错误的赋值
[ILINK32错误]错误:无法解决的外部'从\PROFILES.SOIT.LOCAL\HOMES $ \SIMON.CANNING\MY DOCUMENTS\RAD STUDIO\PROJECTS\DEBUG\FILE1.OBJ
[ILINK32错误]错误:无法执行链接


我知道这是由于构造函数调用而发生的。

解决方案

对于所有的电视剧,您可能会得到很多建议,请问如何解决这个问题?然后执行序列化所需要做的所有事情,我个人都不必理会。

只需将大小设置为标头,写出到文件中,然后



在加载时,读入标头,将矢量调整为它所说的大小,然后读入矢量的字节。



[edit]



如评论中所述,您必须意识到自己不能也可以将其他非平凡类型(例如字符串)写为二进制。所有这些都必须序列化。我从您提出问题的方式推断出,您已经意识到了这一点。



因此,如果您只需要序列化一些类型而不必使用Boost,我个人认为使用Boost解决这个问题会太过分了。人们似乎对我表达这种观点的方式做出了消极反应,所以也许他们从来不需要处理一个项目,该项目中有人依靠boost序列化来解决一个非常简单和孤立的问题=)



您真正需要的是一些简单的支持功能,您可以自己编写。在这种情况下,您甚至根本不需要该标头来包含矢量大小,因为您可以序列化...

  //这将编写一个琐碎的数据类型向量。 
模板< class T>
void WriteTrivial(std :: ostream& s,const std :: vector< T& data))
{
unsigned int len = data.size();
s.write((char *)& len,sizeof(len));
s.write((const char *)& data [0],len * sizeof(T));
}

//读取简单数据类型的向量。
模板< class T>
void ReadTrivial(std :: istream& s,std :: vector< T& data))
{
unsigned int len = 0;
s.read((char *)& len,sizeof(len));
data.resize(len);
if(len> 0)s.read((char *)& data [0],len * sizeof(T));
}

如果向量可能包含字符串或向量,则需要更多支持功能

  //这将写入非平凡数据类型的向量。 
模板< class T>
void Write(std :: ostream& s,const std :: vector< T& data))
{
unsigned int len = data.size();
s.write((char *)& len,sizeof(len));
for(unsigned int i = 0; i Write(s,data [i]);
}
}

// //读取非平凡数据类型的向量。
模板< class T>
void Read(std :: istream& s,std :: vector& T& data)
{
unsigned int len = 0;
s.read((char *)& len,sizeof(len));
data.resize(len);
for(unsigned int i = 0; i Read(s,data [i]);
}
}

当然,以上所述您还需要一些字符串,以及用于处理常规数据类型的读/写模板。无论如何,这应该会让您入门。希望有帮助。





现在您已经发布了自己的代码,我建议这样做:



日历中:

  void loadFromFile()
{
ifstream iStream( file.ext,ios :: binary);
if(!iStream)
{
cout<< 无文件;
} else {
fileHeader_t fHeader;
iStream.read((char *)& fHeader,sizeof(fileHeader_t));
if(fHeader.magicNumber!= 0xDEADBEAF)返回;
约会.resize(fHeader.appointmentCount);
for(size_t i = 0; i<约会.size(); i ++){
约会[i] .read(iStream);
}
iStream.close();
}
}

void saveToFile()
{
ofstream oStream( file.ext,ios :: binary);
fileHeader_t fHeader;
fHeader.magicNumber = 0xDEADBEAF;
fHeader.appointmentCount =约会.size();
oStream.write((char *)& fHeader,sizeof(fileHeader_t));
for(size_t i = 0; i<约会.size(); i ++){
约会[i] .write(oStream);
}
oStream.close();
}

现在,用于序列化字符串:

  void write(ostream& s,const string& str)
{
unsigned int len = str.size();
s.write((char *)& len,sizeof(len));
s.write(str.c_str(),len * sizeof(char));
}

void read(istream& s,string& str)
{
unsigned int len = 0;
s.read((char *)& len,sizeof(len));
str.resize(len);
if(len == 0)return;
s.read((char *)str.c_str(),len * sizeof(char));
}

也许是写一些简单类型的有用包装:

 模板< class T> 
void writeTrivial(ostream& s,const T& val)
{
ostream.write((const char *)& val,sizeof(T));
}

模板< class T>
void readTrivial(ostream& s,T& val)
{
ostream.read((char *)& val,sizeof(T));
}

最后,在约会

  void write(ostream& s)
{
writeTrivial(s,appDateTime);
writeTrivial(s,appReminderDateTime);
write(s,appType);
write(s,appLocation);
write(s,appComments);
writeTrivial(s,appIsImportant);
}

void read(istream& s)
{
readTrivial(s,appDateTime);
readTrivial(s,appReminderDateTime);
read(s,appType);
读取(s,appLocation);
读取(s,appComments);
readTrivial(s,appIsImportant);
}


I am using C++ Builder and I have a vector array of Appointment objects.

I want to save it to and load it from a file.

Currently, I am using ifstream and ofstream with binary files. I have a header that contains the size of the vector that will be saved alongside the data, so as to know its size when loading.

Is serilization a better way to do this?

If so, do I need to use the boost library, or another way?

Here is my current code:

class appointment
{
public:
    appointment();
    appointment(TDateTime aDate, TDateTime aReminderDateTime, string aType,
    string aLocation, string aComments, bool aIsImportant)
    {
        appDateTime = aDate;
        appReminderDateTime = aReminderDateTime;
        appType = aType;
        appLocation = aLocation;
        appComments = aComments;
        appIsImportant = aIsImportant;
    }
    void setAppDateTime(TDateTime aDateTime)
    {
        appDateTime = aDateTime;
    }
    void setappReminderDateTime(TDateTime aReminderDateTime)
    {
        appReminderDateTime = aReminderDateTime;
    }
    /*
    void printAppointmentDetails()
    {
        cout << "Appointment Date: " << appDateTime << endl;
        cout << "Appointment Reminder Date: " << appReminderDateTime << endl;
        cout << "Appointment Type: " << appType << endl;
        cout << "Appointment Location: " << appLocation << endl;
        cout << "Appointment Comments: " << appComments << endl;
        if (appIsImportant)
        {
            cout << "Appointment IsImportant: " << "Yes" << endl;
        } else {
            cout << "Appointment IsImportant: " << "No" << endl;
        }
    }

    */
    void setType(string aType)
    {
        appType = aType;
    }
    void setLocation(string aLocation)
    {
        appLocation = aLocation;
    }
    void setComments(string aComments)
    {
        appComments = aComments;
    }
    void setIsImportant(bool aIsImportant)
    {
        appIsImportant = aIsImportant;
    }
    TDateTime getAppDateTime()
    {
        return appDateTime;
    }
    TDateTime getAppReminderDateTime()
    {
        return appReminderDateTime;
    }
    string getType()
    {
        return appType;
    }
    string getLocation()
    {
        return appLocation;
    }
    string getComments()
    {
        return appComments;
    }
    bool getIsImportant()
    {
        return appIsImportant;
    }
private:
    //appointment();
    TDateTime appDateTime;
    TDateTime appReminderDateTime;
    string appType;
    string appLocation;
    string appComments;
    bool appIsImportant;
    //person owner;
};

class calendar
{
public:
    calendar()
    {
        //loadFromFile();
        //load persons
        //calculateimportantAppointments
    }
    ~calendar()
    {
        saveToFile();
    }
    //addperson
    //editperson
    //removeperson
    void createAppointment(TDateTime aDate, TDateTime aReminderDateTime, string aType,
    string aLocation, string aComments, bool aIsImportant)
    {
        appointment newAppointment(aDate, aReminderDateTime, aType,
        aLocation, aComments, aIsImportant);
        appointments.push_back(newAppointment);
    }
    /*
    void printAllAppointmentDetails()
    {
        for (int i = 0; i < appointments.size(); i++)
        {
            appointments[i].printAppointmentDetails();
        }
    }
    void calculateImportantAppointments()
    {

    }
    int getNumberOfImportantAppointments()
    {
        int intImportantAppointmentCount = 0;
        for (int i = 0; i < appointments.size(); i++)
        {
             if (appointments[i].getIsImportant())
                intImportantAppointmentCount += 1;
        }
        return intImportantAppointmentCount;
    }

    appointment[] getImportantAppointments()
    {

    }
    appointment[] getAllAppointments()
    {

    }
    */
    void loadFromFile()
    {
        ifstream iStream("file.ext", ios::binary);
        if (!iStream)
        {
            cout << "No file";
        } else {
            fileHeader_t fHeader;
            iStream.read((char*)&fHeader, sizeof(fileHeader_t));
            if (fHeader.magicNumber = 0xDEADBEAF)
            {
                appointments.resize(fHeader.appointmentCount);
                iStream.read((char*)&appointments[0], fHeader.appointmentCount * sizeof(appointment));
            }
        }
    }
    void saveToFile()
    {
        ofstream oStream("file.ext", ios::binary);
        fileHeader_t fHeader;
        fHeader.magicNumber = 0xDEADBEAF;
        fHeader.appointmentCount = appointments.size();
        oStream.write((char*)&fHeader, sizeof(fileHeader_t));
        oStream.write((char*)&appointments[0], sizeof(appointment) * appointments.size());
    }
    //vector<appointment> appointments;
private:
    vector<appointment> appointments;
    string calCurrentDate;
    string calCurrentTime;
    typedef struct fileHeader_s
    {
        DWORD magicNumber;
        size_t appointmentCount;
    }fileHeader_t;
};

I am getting thew following errors when calling the loadFromFile() method.

[BCC32 Warning] File1.cpp(185): W8060 Possibly incorrect assignment [ILINK32 Error] Error: Unresolved external 'appointment::appointment()' referenced from \PROFILES.SOIT.LOCAL\HOMES$\SIMON.CANNING\MY DOCUMENTS\RAD STUDIO\PROJECTS\DEBUG\FILE1.OBJ [ILINK32 Error] Error: Unable to perform link

I understand that this happens because of the constructor call. Can I please have some advice on how to fix this issue?

解决方案

With all the dramas you may have getting boost to compile, and then all the guff you have to do to implement serialization, I personally don't bother.

Just set the size into your header, write it out to file, then write out your vector's bytes.

When loading, read in the header, resize the vector to what it says, and then read in the vector's bytes.

[edit]

As discussed in the comments, you must be aware that you can't write out other non-trivial types (such as strings) as binary either. All these must be serialized. I had inferred, from the way you posed your question, that you were already aware of this.

So if you only need to serialize a few types and don't already use boost, I personally believe that using boost to solve this problem will be overkill. People seem to have responded negatively to the way in which I expressed this opinion, so maybe they have never had to deal with a project where somebody built in a dependence on boost serialization to solve a really simple and isolated problem =)

What you really need is a handful of simple support functions which you can write yourself. You don't even really need that header to contain the vector size in this case because you can serialize...

// This writes a vector of trivial data types.
template <class T>
void WriteTrivial( std::ostream& s, const std::vector<T>& data )
{
    unsigned int len = data.size();
    s.write( (char*)&len, sizeof(len) );
    s.write( (const char*)&data[0], len * sizeof(T) );
}

// This reads a vector of trivial data types.
template <class T>
void ReadTrivial( std::istream& s, std::vector<T>& data )
{
    unsigned int len = 0;
    s.read( (char*)&len, sizeof(len) );
    data.resize(len);
    if( len > 0 ) s.read( (char*)&data[0], len * sizeof(T) );
}

If your vector might contain strings or vectors, you need a few more support functions

// This writes a vector of non-trivial data types.
template <class T>
void Write( std::ostream& s, const std::vector<T>& data )
{
    unsigned int len = data.size();
    s.write( (char*)&len, sizeof(len) );
    for( unsigned int i = 0; i < len; i++ ) {
        Write( s, data[i] );
    }
}

// This reads a vector of non-trivial data types.
template <class T>
void Read( std::istream& s, std::vector<T>& data )
{
    unsigned int len = 0;
    s.read( (char*)&len, sizeof(len) );
    data.resize(len);
    for( unsigned int i = 0; i < len; i++ ) {
        Read( s, data[i] );
    }
 }

And of course with the above you need something for strings, and a Read/Write template to handle normal data types. This should get you started anyway. Hope that helps.

[edit]

Now that you have posted your code, I suggest this:

In Calendar:

void loadFromFile()
{
    ifstream iStream("file.ext", ios::binary);
    if (!iStream)
    {
        cout << "No file";
    } else {
        fileHeader_t fHeader;
        iStream.read((char*)&fHeader, sizeof(fileHeader_t));
        if (fHeader.magicNumber != 0xDEADBEAF) return;
        appointments.resize(fHeader.appointmentCount);
        for( size_t i = 0; i < appointments.size(); i++ ) {            
            appointments[i].read(iStream);
        }
        iStream.close();
    }
}

void saveToFile()
{
    ofstream oStream("file.ext", ios::binary);
    fileHeader_t fHeader;
    fHeader.magicNumber = 0xDEADBEAF;
    fHeader.appointmentCount = appointments.size();
    oStream.write((char*)&fHeader, sizeof(fileHeader_t));
    for( size_t i = 0; i < appointments.size(); i++ ) {            
        appointments[i].write(oStream);
    }
    oStream.close();
}

Now, for serialising strings:

void write( ostream &s, const string& str )
{
    unsigned int len = str.size();
    s.write((char*)&len, sizeof(len));
    s.write(str.c_str(), len*sizeof(char));
}

void read( istream &s, string& str )
{
    unsigned int len = 0;
    s.read((char*)&len, sizeof(len));
    str.resize(len);
    if( len == 0 ) return;
    s.read((char *) str.c_str(), len*sizeof(char));
}

And maybe a helpful wrapper for writing trivial types:

template <class T>
void writeTrivial( ostream& s, const T& val )
{
    ostream.write( (const char*)&val, sizeof(T) );
}

template <class T>
void readTrivial( ostream& s, T& val )
{
    ostream.read( (char*)&val, sizeof(T) );
}

And finally, in Appointment

void write( ostream& s )
{
    writeTrivial(s, appDateTime);
    writeTrivial(s, appReminderDateTime);
    write(s, appType);
    write(s, appLocation);
    write(s, appComments);
    writeTrivial(s, appIsImportant);
}

void read( istream& s )
{
    readTrivial(s, appDateTime);
    readTrivial(s, appReminderDateTime);
    read(s, appType);
    read(s, appLocation);
    read(s, appComments);
    readTrivial(s, appIsImportant);
}

这篇关于将向量加载并保存到文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆