現在開始做序列化的讀,也即是反序列化,本來爲沒個序列化的類設計了2個序列化接口函數:
//序列化接口
virtual void GetObjectData(CJSerializationInfo* info) {}
virtual void DeSerializationObjectData(CJSerializationInfo* info) {}
可突然發現,其實DeSerializationObjectData是沒必要存在的,在.net中,每個對象都是引用,所以它可以爲每個對象創建新的實例,然後再賦值,可C++中不可以啊,因爲我有些對象包括上層類的實例中,它已經不需要再去實例化了。,所以在反序列化的時候,很多對象不能直接new,而必須從宿主對象中獲取。只有哪些動態生成的對象纔可以new。
中心思想有了,開始實現吧。
首先定義對象讀取類
class CObjectRead
{
public:
class ObjectMemberValue
{
public:
juint32 TypeID;
juint32 Valuetypeid;
CJObject* pValue;
};
CObjectRead(CSerialization* pSer,jint32 id,CJStream* pStream);
void Read(jbyte headercode);
CJSerializationInfo* ReadObjectSerializationInfos();
void ReadPrimitive(CJSerializationInfo* pSerInfo,CJSerializationInfo* currentObjSInfo,int index,jbyte typecode);
public:
CSerialization* m_pSerialization;
CJObject* m_pObj;
CJObject* m_pParentObj;
CJStream* m_pStream;
jint32 m_ObjID;
CJList m_ObjectMemberValues;
};
它的基本作用就是讀取一個對象,並把它放到對象實例映射 表中去(在CSerialization對象中),具體過程:
反序列化入口函數:CSerialization的DeSerialize
CJObject* CSerialization::DeSerialize(CJStream* pStream)
{
jint32 head;
CJObject* pTopObj = JNULL;
if(!pStream->ReadInt32(&head))return JNULL;
if(head != 0xFF78FF78)return JNULL;
char c;
pStream->ReadChar(&c);if(c != 'J')return JNULL;
pStream->ReadChar(&c);if(c != 'H')return JNULL;
pStream->ReadChar(&c);if(c != 'M')return JNULL;
pStream->ReadChar(&c);if(c != 'F')return JNULL;
//確認是我們的序列化數據
jbool readend = FALSE;
jbyte headtype;
while(pStream->ReadByte(&headtype))
{
switch(headtype)
{
case SER_HRADERTYPE_OBJINFO:
{
CObjectRead obread(this,-1,pStream);
AddObjectSerializationInfos(obread.ReadObjectSerializationInfos());
}
break;
case SER_HRADERTYPE_BASEDATA:
case SER_HRADERTYPE_ARRAY:
case SER_HRADERTYPE_OBJHEADER:
{
CObjectRead obread(this,-1,pStream);
obread.Read(headtype);
}
break;
case SER_HRADERTYPE_END:
readend = TRUE;
goto DeSerializeEnd;
break;
default:
if(headtype >= SER_HRADERTYPE_OBJMEMBER && headtype <= SER_HRADERTYPE_String)
{
}
else
{
JThrowSerialException("序列化數據被破壞");
}
break;
}
}
DeSerializeEnd:
if(readend)
{
CHasReadedObject* pTopReadObj = GetHasReadedObject(topID);
JASSERT(pTopReadObj != JNULL);
pTopObj = pTopReadObj->m_pObject;
//修復所有對象
CJListT<jint64>* keys = this->m_FixingObjects.GetKeys();
for(int i = 0;i < keys->GetCount();i++)
{
CHasReadedObject* pReadObj = (CHasReadedObject*)m_FixingObjects.GetHashObject(0,(*keys)[i]);
JASSERT(pReadObj != JNULL && pReadObj->m_pObject != JNULL);
if(pReadObj->m_pObject->GetType().IsArray())
{
//指針數組需要特殊處理
CJObjectArray* pArray = (CJObjectArray*)pReadObj->m_pObject;
for(int j = 0;j < pArray->GetLength();j++)
{
CJObject* pitem = pArray->GetItem(j);
if(pitem->GetType() == JTYPEOF(CFixObject))
{
CFixObject* pfix = (CFixObject*)pitem;
CHasReadedObject* preaded = GetHasReadedObject(pfix->m_ObjectID);
JASSERT(preaded != JNULL);
pArray->SetItem(preaded->m_pObject,j);
delete pitem;
}
}
}
else
{
//首先獲取序列化信息
CJSerializationInfo* currentObjSInfo = GetCurrentObjectSerializationInfos(pReadObj->m_typeID,pReadObj->m_pObject);
JASSERT(currentObjSInfo != JNULL);
for(int i = 0;i < currentObjSInfo->GetStatisticsCount();i++)
{
if(((SerializationInfoField*)currentObjSInfo->m_fields[i])->fieldTypeID == FIELDTYPE_OBJPTR)
{
CJObject** pfObj = (CJObject**)currentObjSInfo->GetFieldObject(pReadObj->m_pObject,i);
if(pfObj == JNULL)continue;
if(*pfObj == JNULL)continue;
if((*pfObj)->GetType() == JTYPEOF(CFixObject))
{
//修復引用
CFixObject* pfix = (CFixObject*)*pfObj;
CHasReadedObject* preaded = GetHasReadedObject(pfix->m_ObjectID);
JASSERT(preaded == JNULL);
*pfObj = preaded->m_pObject;
delete pfix;
}
}
}
}
}
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&資源清除&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//刪除當前庫類型序列化信息
//刪除文件庫類型序列化信息
//刪除讀取對象實例映射表
return pTopObj;
}
這個函數目的很簡單,首先做格式判斷,然後開始一個一個的讀取對象(和對象序列化格式信息),真正讀取對象:
void CObjectRead::Read(jbyte headercode)
{
jint64 ll = m_pStream->GetPosition();
jint32 typeID,id,parentid,findex;
if(!m_pStream->ReadInt32(&typeID))JThrowSerialException("序列化數據被破壞");
if(!m_pStream->ReadInt32(&id))JThrowSerialException("序列化數據被破壞");
if(!m_pStream->ReadInt32(&parentid))JThrowSerialException("序列化數據被破壞");
if(!m_pStream->ReadInt32(&findex))JThrowSerialException("序列化數據被破壞");
//根據類型ID此時可以確認對象類型了,而且對象類型信息應該已經存在於映射表中了
CJSerializationInfo* pObSerInfos = m_pSerialization->GetObjectSerializationInfos(typeID);
if(pObSerInfos == JNULL)JThrowSerialException("序列化內核異常:對象類型信息丟失,數據被破壞");
//此時比較複雜,處理需反覆斟酌
if(parentid > 0)
{
//有父對象,此時,父對象已經產生,從父對象中獲取實例
CHasReadedObject* pParentObj = m_pSerialization->GetHasReadedObject(parentid);
if(pParentObj == JNULL || pParentObj->m_pObject == JNULL)JThrowSerialException("序列化內核錯誤:無法找到父對象");
CJSerializationInfo* parentSinfo = m_pSerialization->GetObjectSerializationInfos(pParentObj->m_typeID);
if(parentSinfo == JNULL)JThrowSerialException("序列化內核錯誤:無法找到父對象序列化信息(此時程序應該已經保證父對象類型序列化信息已經被讀取)");
CJSerializationInfo* currentParentSInfo = m_pSerialization->GetCurrentObjectSerializationInfos(pParentObj->m_typeID,pParentObj->m_pObject);
m_pObj = currentParentSInfo->GetFieldObject(pParentObj->m_pObject,parentSinfo->GetFieldInfo(findex)->name);
if(m_pObj == JNULL)
{
//有父對象,但確找不到自己的實例,唯一的可能是版本不一致,用戶程序去除了該字段的序列化
}
}
else
{
//創建該對象
CJObject* pnewObj = CJActivator::CreateInstance(pObSerInfos->m_Name);
//需要做外部實例化處理,現在不做,待續
if(pnewObj == JNULL)JThrowSerialException(CJString::FormatString("序列化異常:無法創建%s對象",pObSerInfos->m_Name));
m_pObj = pnewObj;
}
CHasReadedObject* pObjRead = m_pSerialization->AddReadedInstances(m_pObj,typeID,id,parentid);
if(headercode == SER_HRADERTYPE_OBJHEADER)
{
//增加到對象映射表
CJSerializationInfo* currentObjSInfo = m_pSerialization->GetCurrentObjectSerializationInfos(typeID,m_pObj);
jbool objectconplete = TRUE;
//開始讀取成員
if(pObSerInfos->GetStatisticsCount() > 0)
{
//強制性初始化,將對象中的參與反序列化的引用(指針)初始化爲空
if(m_pObj != JNULL)
{
for(int i = 0;i < currentObjSInfo->GetStatisticsCount();i++)
{
if(((SerializationInfoField*)currentObjSInfo->m_fields[i])->fieldTypeID == FIELDTYPE_OBJPTR)
{
CJObject** pfObj = (CJObject**)currentObjSInfo->GetFieldObject(m_pObj,i);
if(pfObj == JNULL)continue;
*pfObj = JNULL;
}
}
}
jbyte membetype;
for(int i = 0;i < pObSerInfos->GetStatisticsCount();i++)
{
jint64 ll1 = m_pStream->GetPosition();
if(!m_pStream->ReadByte(&membetype))JThrowSerialException("序列化內核異常:對象成員讀取失敗,數據被破壞");
while(membetype == SER_HRADERTYPE_OBJINFO)
{
m_pSerialization->AddObjectSerializationInfos(ReadObjectSerializationInfos());
if(!m_pStream->ReadByte(&membetype))JThrowSerialException("序列化內核異常:對象成員讀取失敗,數據被破壞");
}
switch(membetype)
{
case SER_HRADERTYPE_OBJMEMBER:
{
//對象,該對象存儲在其他地方,此時,該對象已經被實例化了
}
break;
case SER_HRADERTYPE_OBJMEMBERPTR:
{
jint32 memberid,memberindex;
m_pStream->ReadInt32(&memberid);
m_pStream->ReadInt32(&memberindex);
if(m_pObj != JNULL)
{
CJObject* pMemberObj = JNULL;
pMemberObj = currentObjSInfo->GetFieldObject(m_pObj,pObSerInfos->GetFieldInfo(memberindex)->name);
if(pMemberObj != JNULL)
{
CJObject** ppMemberObj = (CJObject**)pMemberObj;
CHasReadedObject* pReadedMembetObj= m_pSerialization->GetHasReadedObject(memberid);
if(pReadedMembetObj != JNULL)
{
//如果對象已經存在
*ppMemberObj = pReadedMembetObj->m_pObject;
}
else
{
CFixObject* fixObj = new CFixObject();
fixObj->m_ObjectID = memberid;
*ppMemberObj = fixObj;
//增加到待修復隊列
if(objectconplete)
{
m_pSerialization->AddToFix(pObjRead);
}
objectconplete = FALSE;
}
}//確定該字段存在
}//確定該對象實例存在
}
break;
default:
if(membetype >= SER_HRADERTYPE_Boolean && membetype <= SER_HRADERTYPE_String)
{
ReadPrimitive(pObSerInfos,currentObjSInfo,i,membetype);
}
else
{
JThrowSerialException("序列化異常:不識別的頭類型");
}
break;
}
}
}
}
else if(headercode == SER_HRADERTYPE_ARRAY)
{
CJObjectArray* pArray = (CJObjectArray*)m_pObj;
jint32 length;
if(!m_pStream->ReadInt32(&length))JThrowSerialException("序列化數據被破壞");
if(length > 0)
{
for(int i = 0;i < length;i++)
{
jint32 id;
if(!m_pStream->ReadInt32(&id))JThrowSerialException("序列化數據被破壞");
if(pArray == JNULL)continue;
CFixObject* fixObj = new CFixObject();
fixObj->m_ObjectID = id;
pArray->AddItem(fixObj);
}
if(m_pObj != JNULL)
{
m_pSerialization->AddToFix(pObjRead);
}
}
}
else if(headercode == SER_HRADERTYPE_BASEDATA)
{
CJBaseDataType* pBaseObj = (CJBaseDataType*)m_pObj;
jbool bnew = FALSE;
if(pBaseObj == JNULL)
{
//也許該對象不存在,也許該字段不存在了,此時讀取,只爲兼容格式,不保存信息
pBaseObj = (CJBaseDataType*)CJActivator::CreateInstance(pObSerInfos->m_Name);
if(pBaseObj == JNULL)JThrowSerialException(CJString::FormatString("序列化異常:無法創建%s對象",pObSerInfos->m_Name));
bnew = TRUE;
}
CJArchive ar(m_pStream);
pBaseObj->DeSerialize(&ar);
if(bnew)
{
CJActivator::ReleaseInstance(pBaseObj);
}
}
else
{
JThrowSerialException("序列化異常:不識別的對象類型頭");
}
}
這個函數有點長了,看註釋基本上可以明白內容,看看讀取對象序列化類型信息
CJSerializationInfo* CObjectRead::ReadObjectSerializationInfos()
{
CJSerializationInfo* pObjSerinfos = new CJSerializationInfo();
jint32 fieldcount;
if(!m_pStream->ReadString(&pObjSerinfos->m_Name))JThrowSerialException("序列化數據被破壞");
if(!m_pStream->ReadInt32(&pObjSerinfos->m_typeID))JThrowSerialException("序列化數據被破壞");
if(!m_pStream->ReadInt32(&fieldcount))JThrowSerialException("序列化數據被破壞");
if(fieldcount > 0)
{
for(int i = 0;i < fieldcount;i++)
{
SerializationInfoField* field = new SerializationInfoField;
m_pStream->ReadUInt32(&field->fieldTypeID);
m_pStream->ReadUInt32(&field->valuetypeid);
m_pStream->ReadString(&field->name);
pObjSerinfos->m_fields.Add(field);
}
}
return pObjSerinfos;
}
對於CJSerializationInfo對象,我們有2個,一個是從文件(二進制)中獲取,一個是從程序中調用對象的GetObjectData獲取,
爲什麼會有2個呢,因爲他們可能不一致,所以在讀取的時候是以文件(二進制)中保存的信息爲準,而在賦值的時候是以GetObjectData獲取的爲準,這樣可以解決版本兼容問題,而且反序列化程序不會因爲格式變換而亂。
以上工作,基本上完成了序列化所有主要的工作,其他工作(如資源釋放等)以後做.下次要開始調試,測試工作了。