首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MFC 序列化進階(二):物件簽名與版本控制

     編輯:關於C語言

問題:誤讀無效資料檔

若資料檔格式不符(如缺少欄位、型別錯誤),單純 Serialize() 僅回傳 ERROR,無法精確定位錯誤原因。

解決方案 1:物件簽名

在類別定義靜態常數簽名字串,序列化時優先寫入/讀取簽名,驗證一致性。

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,區別於一般讀寫錯誤。

解決方案 2:版本號

類別演進時新增/刪除欄位,舊版資料檔仍需相容。引入版本號實現前向相容。

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 新增欄位
}

最佳實務

  • 簽名確保「正在讀取正確類型的物件」。
  • 版本號確保「能正確解讀該版本的資料結構」。
  • 簽名建議使用無明顯業務關聯的隨機字串(增加反序列化難度)。
  • 公司層面應建立簽名註冊機制,避免不同類別撞名。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved