[英]Reading/writing files to/from a struct/class
我想將文件讀入struct或class中,但是經過一番閱讀,我發現這樣做不是一個好主意:
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();
}
這聽起來像是我不想執行此操作的原因是因為即使我的結構的數據成員加起來最多為18個字節,其中一些可能仍會被內存中的額外字節填充。 有沒有更正確/優雅的方法可以將文件放入這樣的類/結構中?
首選的通用技術稱為序列化。
它不如二進制表示那么脆弱。 但是它具有需要解釋的開銷。 標准類型可以很好地與序列化一起使用,建議您對類進行序列化,以便可以輕松地對包含您的類的類進行序列化。
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.
}
答案是:這個問題沒有靈丹妙葯。
消除填充以確保類中的數據成員可以使用的一種方法(在使用的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...
我創建了這些宏后面的代碼,這些代碼暫時不共享,但是一個聰明的人可以創建自己的代碼,以將命名的流保存到無序集中。 我發現這是一種完美的方法,因為如果您向類中添加或減去數據成員,則保存/加載不依賴於二進制表示形式和保存順序,因為如果依次保存該類,則類會隨着時間的推移而不斷發展。是您將要面對的問題。
我希望這有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.