1

ファイルを構造体またはクラスに読み込みたいのですが、いくつか読んだ後、次のようなことをするのは良い考えではないことがわかりました。

int MyClass::loadFile( const char *filePath ) {

            ifstream file ( filePath, ios::in | ios::binary );

            file.read ((char*)this, 18);

            file.close();

            return 0;

        }

構造体/クラスからファイルを書きたい場合、これもコーシャーではないと思います:

void MyClass::writeFile( string fileName ) {

        ofstream file( fileName, ofstream::binary ); 

        file.write((char*)this, 18);

        file.close();

    }

これをしたくない理由は、構造体のデータ メンバーが 18 バイトまで追加されたとしても、それらの一部がメモリ内の余分なバイトでパディングされる可能性があるためです。このようなクラス/構造体にファイルを取得するためのより正確でエレガントな方法はありますか?

4

2 に答える 2

3

推奨される一般的な手法は、シリアライゼーションと呼ばれます。

バイナリ表現よりも脆弱ではありません。ただし、解釈する必要があるというオーバーヘッドがあります。標準型はシリアル化に適しているため、クラスを含むクラスを簡単にシリアル化できるように、クラスをシリアル化することをお勧めします。

class MyClass {
     int x;
     float y;
     double z;
     friend std::ostream& operator<<(std::ostream& s, MyClass const& data);
     friend std::istream& operator>>(std::istream& s, MyClass& data);
};

std::ostream& operator<<(std::ostream& s, MyClass const& data)
{
    // Something like this
    // Be careful with strings (the input>> and output << are not symmetric unlike other types)
    return str << data.x << " " << data.y << " " << data.z << " ";
}

// The read should be able to read the version printed using <<
std::istream& operator>>(std::istream& s, MyClass& data)
{
    // Something like this
    // Be careful with strings.
    return str >> data.x >> data.y >> data.z;
}

使用法:

int main()
{
    MyClass   plop;
    std::cout << plop;  // write to a file
    std::cin  >> plop;  // read from a file.


    std::vector<MyClass>  data;

    // Read a file with multiple objects into a vector.
    std::ifstream  loadFrom("plop");
    std::copy(std::istream_iterator<MyClass>(loadFrom), std::istream_iterator<MyClass>(),
              std::back_inserter(data)
             );


    // Write a vector of objects to a file.
    std::ofstream   saveTo("Plip");
    std::copy(data.begin(), data.end(), std::ostream_iterator<MyClass>(saveTo));

    // Note: The stream iterators (std::istream_iterator) and (std::ostream_iterator)
    //       are templatized on your type. They use the stream operators (operator>>)
    //       and (operator<<) to read from the stream.
}
于 2013-07-26T23:44:47.920 に答える
0

答えは次のとおりです。この問題に特効薬はありません。

パディングをなくして、クラスのデータメンバーが使用されるようにする1つの方法(使用しているMSVCで)

#pragma pack( push, 1 )

class YourClass {
    // your data members here
    int Data1;
    char Data2;
    // etc...
};

#pragma pack( pop )

このアプローチの主な有用性は、クラスがビットマップ ヘッダーなどの事前定義された形式と一致する場合です。猫や犬などを表す汎用クラスの場合は、このアプローチを使用しないでください。これを行う場合の他のことは、コンパイラのデータ型のバイト単位の長さを確認することです。コードがマルチプラットフォームになる場合は、__int32 などのメンバーに明示的なサイズを使用する必要があります。

これが一般的なクラスの場合、save メンバーでは、各値を明示的に記述する必要があります。これを行うためのヒントは、sourceforge またはどこかでこれを行うのに役立つ適切なコードを作成または取得することです。理想的には、メンバーに名前を付けることができるいくつかのコードで、次のようなものを使用します。

SET_WRITE_DOUBLE( L"NameOfThing", DoubleMemberOfClass );
SET_WRITE_INT( L"NameOfThing2", IntMemberOfClass );
// and so on...

私はこれらのマクロの背後にあるコードを作成しました。今は共有していませんが、賢明な人は独自のコードを作成して、named を unordered-set でストリームに保存できます。私が見つけたこれは完璧なアプローチです。なぜなら、クラスにデータメンバーを追加または削除する場合、セーブ/ロードはバイナリ表現とセーブの順序に依存しないためです。直面する問題です。

これが役立つことを願っています。

于 2013-07-26T23:34:28.973 に答える