向/从结构/类读取/写入文件

时间:2013-07-26 23:11:13

标签: c++ class struct ifstream ofstream

我想将一个文件读入一个结构或类,但经过一些阅读后,我已经收集到这样做的好主意:

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

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

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

            file.close();

            return 0;

        }

我猜我是否想要从struct / class写一个文件,这不是犹太人:

void MyClass::writeFile( string fileName ) {

        ofstream file( fileName, ofstream::binary ); 

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

        file.close();

    }

这听起来像是我不想这样做的原因是因为即使我的struct的数据成员加起来为18个字节,其中一些可能会在内存中填充额外的字节。是否有更正确/更优雅的方式将文件放入类/结构中?

2 个答案:

答案 0 :(得分:2)

首选的通用技术称为序列化。

它比二进制表示更脆弱。但它需要解释的开销。标准类型适用于序列化,我们鼓励您对类进行序列化,以便可以轻松地序列化包含类的类。

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

答案 1 :(得分:0)

答案是:这个问题没有灵丹妙药。

一种可以消除填充的方法,以确保您的类中的数据成员使用(在您正在使用的MSVC中)

#pragma pack( push, 1 )

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

#pragma pack( pop )

此方法的主要用途是,如果您的类匹配预定义的格式,例如位图标头。如果它是代表猫,狗的通用类,那么不管怎么说都不要使用这种方法。如果这样做的另一件事是确保你知道编译器的数据类型的字节长度,如果你的代码永远是多平台,那么你应该为成员使用显式大小,如__int32等。

如果这是一般类,那么在保存成员中,应该显式写入每个值。这样做的一个提示是创建或从sourceforge或某个好的代码获取,以帮助做到这一点。理想情况下,一些允许成员命名的代码,我使用类似的东西:

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

我创建了这些宏背后的代码,我现在不分享,但是聪明的人可以创建自己的代码来保存命名为无序集中的流。我发现这是一个完美的方法,因为如果你向类中添加或减去数据成员,保存/加载不依赖于二进制表示和保存的顺序,因为如果你按顺序保存,你的类无疑会随着时间的推移而发展是你将面临的一个问题。

我希望这会有所帮助。