自定義 序列化3

現在開始做序列化的讀,也即是反序列化,本來爲沒個序列化的類設計了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獲取的爲準,這樣可以解決版本兼容問題,而且反序列化程序不會因爲格式變換而亂。

以上工作,基本上完成了序列化所有主要的工作,其他工作(如資源釋放等)以後做.下次要開始調試,測試工作了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章