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

问题描述

我使用C ++ Builder,我有一个对象Appointment的向量数组。



我想保存并将这个向量加载到文件。



目前我正在使用ifstream和二进制文件。我有一个头,具有的矢量的大小被保存和加载以及知道如何矢量大小的值。



如果是这样,这是一个更好的方法吗?

感谢



这是我当前的代码:

 类约会
{
public:
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< Appintment Date:< appDateTime<< endl
cout<< Appintment Reminder Date:< appReminderDateTime<< endl
cout<< Appintment Type:<< appType<< endl
cout<< Appintment Location:< appLocation<< endl
cout<< Appappment Comments:< appComments<< endl
if(appIsImportant)
{
cout<< Appintment IsImportant:< 是< endl
} else {
cout<< Appintment IsImportant:< 否< 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;
//个人所有者
};

class calendar
{
public:
calendar()
{
// loadFromFile
//加载人
// calculateimportantAppointments
}
〜calendar()
{
saveToFile();
}
// addperson
// editperson
// removeperson
void createAppointment(TDateTime aDate,TDateTime aReminderDateTime,string aType,
string aLocation,string aComments,bool aIsImportant)
{
预约newAppointment(aDate,aReminderDateTime,aType,
aLocation,aComments,aIsImportant);
appointments.push_back(newAppointment);
}
/ *
void printAllAppointmentDetails()
{
for(int i = 0; i< appointmentments.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;
}

预约[] 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)
{
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>约会
private:
vector< appointment>约会
string calCurrentDate;
string calCurrentTime;
typedef struct fileHeader_s
{
DWORD magicNumber;
size_t appointmentCount;
} fileHeader_t;
};



我调用loadFromFile()方法时遇到以下错误。



[BCC32警告] File1.cpp(185):W8060可能不正确的赋值
[ILINK32错误]错误:未解决的外部'引用自\PROFILES.SOIT.LOCAL\HOMES $ \SIMON.CANNING \MY文档\RAD STUDIO\PROJECTS\DEBUG\FILE1.OBJ
[ILINK32错误]错误:无法执行链接



我认为这是因为构造函数调用。

解决方案
>

有了所有的电视剧,你可能会得到提高编译,然后所有的guff你必须做的实现序列化,我个人不打扰。





加载时,读入标题,将向量调整到什么大小它说,然后读向量的字节。





正如在注释中讨论的,你必须意识到你不能把其他非平凡类型(如字符串)写成二进制。所有这些都必须序列化。我已经推断,从你提出你的问题的方式,你已经知道这一点。



所以如果你只需要序列化几种类型,使用boost,我个人相信使用boost来解决这个问题会是过度。人们似乎对我表达这种观点的方式作出了负面反应,所以也许他们从来没有必要处理一个项目,其中某人建立在依赖于升压序列化以解决一个真正简单和孤立的问题=)



你真正需要的是一些简单的支持功能,你可以自己写。你在这种情况下甚至不需要包含向量大小的标题,因为你可以序列化...

  //这写一个简单的数据类型的向量。 
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));
}

//读取一个简单数据类型的向量。
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));
}

如果您的向量可能包含字符串或向量,

  //这写了一个非平凡数据类型的向量。 
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 Write(s,data [i]);
}
}

//读取一个非平凡数据类型的向量。
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 Read(s,data [i]);
}
}

当然, ,以及用于处理正常数据类型的读/写模板。这应该让你开始反正。希望有所帮助。



[edit]



代码,我建议这样做:



日历中:

 code> 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)return;
appointmentments.resize(fHeader.appointmentCount);
for(size_t i = 0; i< appointments.size(); i ++){
appointmentments [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 ++){
appointmentments [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));
}

template< 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);
read(s,appLocation);
read(s,appComments);
readTrivial(s,appIsImportant);
}


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

I am wanting to save and load this vector to a file.

Currently I am using ifstream and ofstream with binary files. I have a header that has the size of the vector that gets saved and loaded as well to know how the value of the vector size. I am having some trouble with this.

Is serilization a better way to do this?

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

Thanks

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 << "Appintment Date: " << appDateTime << endl;
        cout << "Appintment Reminder Date: " << appReminderDateTime << endl;
        cout << "Appintment Type: " << appType << endl;
        cout << "Appintment Location: " << appLocation << endl;
        cout << "Appintment Comments: " << appComments << endl;
        if (appIsImportant)
        {
            cout << "Appintment IsImportant: " << "Yes" << endl;
        } else {
            cout << "Appintment 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 gather that this is because of the constructor call. Can I please have some advice on how to fix this issue.

thanks

解决方案

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

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

07-31 11:32