为CArchive结构序列化添加版本兼容:无版本号存档适配
兼容无版本号旧存档的解决方案
针对旧存档没有前置版本号的情况,核心思路是先尝试读取版本号,验证合理性后选择对应读取逻辑,不合理则回退到旧流程,具体实现如下:
关键修改点
- 将无版本号的旧存档视为
版本1,新版本写入时统一标记为版本2 - 读取时先记录文件指针初始位置,尝试读取版本号后做有效性验证
- 验证失败则回退指针,按旧逻辑读取,避免数据错位导致崩溃
修正后的完整序列化代码
// 序列化(写入):新版本统一写入版本号2 friend CArchive& operator<<(CArchive& rArchive, const S_MEMORIAL_INFO& rsMI) { const WORD wVersion = 2; return rArchive << wVersion << rsMI.strHost << rsMI.strCohost << rsMI.strZoomAttendant << rsMI.strChairman << rsMI.strPrayerOpen << rsMI.strPrayerClose << rsMI.strSpeaker << rsMI.strTheme << rsMI.strImagePath << rsMI.strTextBeforeImage << rsMI.strTextAfterImage << rsMI.iImageWidthAsPercent << rsMI.iSongOpen << rsMI.iSongClose; } // 反序列化(读取):兼容无版本号的旧存档 friend CArchive& operator>>(CArchive& rArchive, S_MEMORIAL_INFO& rsMI) { WORD wVersion = 0; CFile* pFile = rArchive.GetFile(); const LONG originalPos = pFile->GetPosition(); // 记录初始读取位置 // 尝试读取版本号 try { rArchive >> wVersion; } catch (CArchiveException* e) { // 读取版本号失败,直接回退到旧逻辑 e->Delete(); pFile->Seek(originalPos, CFile::begin); goto READ_LEGACY; } // 验证版本号是否合理:只接受1或2(旧版本视为1,新版本是2) if (wVersion != 1 && wVersion != 2) { // 读取到的不是有效版本号,说明是旧存档,回退指针位置 pFile->Seek(originalPos, CFile::begin); goto READ_LEGACY; } // 版本号有效,按版本分支读取 rArchive >> rsMI.strHost >> rsMI.strCohost >> rsMI.strZoomAttendant >> rsMI.strChairman >> rsMI.strPrayerOpen >> rsMI.strPrayerClose >> rsMI.strSpeaker; rsMI.strTheme.Empty(); if (wVersion >= 2) { rArchive >> rsMI.strTheme; } // 读取剩余字段 return rArchive >> rsMI.strImagePath >> rsMI.strTextBeforeImage >> rsMI.strTextAfterImage >> rsMI.iImageWidthAsPercent >> rsMI.iSongOpen >> rsMI.iSongClose; READ_LEGACY: // 旧存档读取逻辑:无版本号,直接按原顺序读取 return rArchive >> rsMI.strHost >> rsMI.strCohost >> rsMI.strZoomAttendant >> rsMI.strChairman >> rsMI.strPrayerOpen >> rsMI.strPrayerClose >> rsMI.strSpeaker >> rsMI.strImagePath >> rsMI.strTextBeforeImage >> rsMI.strTextAfterImage >> rsMI.iImageWidthAsPercent >> rsMI.iSongOpen >> rsMI.iSongClose; }
补充说明
- 版本号验证逻辑:旧存档第一个字段是CString,其序列化开头的int长度值几乎不可能是1或2(空字符串长度为0,同样会触发回退),以此区分新旧存档
- 异常处理:捕获读取版本号时的异常(如文件读取到末尾、数据格式错误),确保程序不会崩溃
- 代码修正:原代码中
operator>>错误使用了const S_MEMORIAL_INFO&参数,反序列化需要修改对象,必须改为S_MEMORIAL_INFO&
内容的提问来源于stack exchange,提问作者Andrew Truckle
相关产品推荐
相关产品推荐

