若資料檔格式不符(如缺少欄位、型別錯誤),單純 Serialize() 僅回傳 ERROR,無法精確定位錯誤原因。
在類別定義靜態常數簽名字串,序列化時優先寫入/讀取簽名,驗證一致性。
class CFoo {
static const CString Signature; // "FooObject"
CString getSignature() const { return Signature; }
// ...
};
const CString CFoo::Signature = "FooObject";
int CFoo::Serialize(CArchive* pArchive) {
int nStatus = SUCCESS;
bool bSigRead = false;
try {
if (pArchive->IsStoring()) {
*pArchive << getSignature(); // 寫入簽名
*pArchive << m_strName << m_nId;
} else {
CString strSig; *pArchive >> strSig; bSigRead = true;
if (strSig != getSignature()) return INVALID_DATAFILE;
*pArchive >> m_strName >> m_nId;
}
} catch (CException* e) {
nStatus = bSigRead ? ERROR : INVALID_DATAFILE;
}
return nStatus;
}
優點:讀取時優先驗證簽名,失敗即回傳 INVALID_DATAFILE,區別於一般讀寫錯誤。
類別演進時新增/刪除欄位,舊版資料檔仍需相容。引入版本號實現前向相容。
class CFoo {
static const CString Signature;
static const int Version; // 1, 2, 3...
// ...
};
const CString CFoo::Signature = "FooObject";
const int CFoo::Version = 1;
if (pArchive->IsStoring()) {
*pArchive << getSignature() << getVersion();
*pArchive << m_strName << m_nId;
// 未來版本可在此追加新欄位
}
else {
CString strSig; *pArchive >> strSig;
if (strSig != getSignature()) return INVALID_DATAFILE;
int nVer; *pArchive >> nVer; bVerRead = true;
if (nVer > getVersion()) return UNSUPPORTED_VERSION; // 檔案版本較新,無法讀取
// 依版本號條件式讀取欄位
*pArchive >> m_strName >> m_nId;
if (nVer >= 2) { *pArchive >> m_newField; } // 版本 2 新增欄位
}