1

私は C++ Builder を使用しており、Appointmentオブジェクトのベクトル配列があります。

ファイルに保存してファイルからロードしたい。

現在、バイナリ ファイルで ifstream と ofstream を使用しています。読み込み時にそのサイズを知るために、データと一緒に保存されるベクターのサイズを含むヘッダーがあります。

シリアル化はこれを行うためのより良い方法ですか?

その場合、boost ライブラリを使用する必要がありますか、それとも別の方法で使用する必要がありますか?

これが私の現在のコードです:

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

loadFromFile() メソッドを呼び出すと、次のエラーが発生します。

[BCC32 警告] File1.cpp(185): W8060 割り当てが間違っている可能性があります [ILINK32 エラー] エラー: \PROFILES.SOIT.LOCAL\HOMES$\SIMON.CANNING\MY DOCUMENTS\ から参照された未解決の外部 'appointment::appointment()' RAD STUDIO\PROJECTS\DEBUG\FILE1.OBJ [ILINK32 エラー] エラー: リンクを実行できません

これは、コンストラクター呼び出しが原因で発生することを理解しています。この問題を解決する方法についてアドバイスをお願いできますか?

4

2 に答える 2

2

あなたがコンパイルするために後押しをしているかもしれないすべてのドラマ、そしてあなたがシリアル化を実装するためにあなたがしなければならないすべてのガフで、私は個人的に気にしません。

サイズをヘッダーに設定し、ファイルに書き込んでから、ベクターのバイトを書き出すだけです。

ロードするときは、ヘッダーを読み取り、ベクターのサイズをその内容に合わせて変更してから、ベクターのバイトを読み込みます。

[編集]

コメントで説明されているように、他の重要なタイプ(文字列など)もバイナリとして書き出すことはできないことに注意する必要があります。これらはすべてシリアル化する必要があります。私はあなたがあなたの質問をした方法から、あなたはすでにこれを知っていたと推測しました。

したがって、いくつかのタイプをシリアル化する必要があり、まだブーストを使用していない場合、この問題を解決するためにブーストを使用するのはやり過ぎだと私は個人的に信じています。人々は私がこの意見を表明した方法に否定的に反応したようです、それでおそらく彼らは誰かが本当に単純で孤立した問題を解決するためにブーストシリアル化への依存を組み込んだプロジェクトに対処する必要がなかったでしょう=)

本当に必要なのは、自分で作成できるいくつかの簡単なサポート機能です。この場合、シリアル化できるため、そのヘッダーにベクトルサイズを含める必要はありません...

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

ベクトルに文字列またはベクトルが含まれている可能性がある場合は、さらにいくつかのサポート関数が必要です

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

そしてもちろん、上記では、文字列用の何かと、通常のデータ型を処理するための読み取り/書き込みテンプレートが必要です。これでとにかく始めることができます。お役に立てば幸いです。

[編集]

あなたがあなたのコードを投稿したので、私はこれを提案します:

カレンダー:_

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

さて、文字列をシリアル化するために:

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

そして、些細なタイプを書くのに役立つラッパーかもしれません。

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

そして最後に、予定で

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);
}
于 2012-09-13T23:58:40.547 に答える
0

セリリゼーションはこれを行うためのより良い方法ですか?

もしそうなら、私はブーストライブラリを使用する必要がありますか、それとも別の方法ですか?

シリアル化ライブラリを使用したほうがいいと思います。この時点でライブラリの使用は制限される可能性がありますが、アプリケーションが大きくなると... C ++ミドルウェアライターは、従来のシリアル化ライブラリのオンライン代替手段です。

于 2012-09-14T15:47:20.643 に答える