シリアル化(Serialization)
12203 ワード
シリアル化(Serialization)転載自:VC知識ベース著者:アヨンシリアル化はマイクロソフトが提供したオブジェクトに対するファイルI/Oのメカニズムであり、フレームワーク/ドキュメント(Document)/ビュー(View)モードでよく応用されている.シリアル化とは何か、オブジェクトをシリアル化する方法、シリアル化機能をどのように使用するかなどの問題がよく分からない人が多い.本論文では,シリアル化について簡単な解釈を試みた.本人はシリアル化機能もあまり使用していないので、不足点はご了承ください.MFCフレーム/ドキュメント/ビュー構造におけるファイル読み書き
CFIleは、MFCクラスライブラリ内のすべてのファイルクラスのベースクラスです.すべてのMFCが提供するファイルI/O機能はこのクラスに関連している.多くの場合、CFIle::Write/WriteHugeを直接呼び出してファイルを書き、CFIle::Read/ReadHugeを呼び出してファイルを読むのが好きです.このようなファイルI/Oは、MFCを使用しないファイルI/Oとあまり変わらず、従来のANSI CのファイルI/Oともあまり変わらず、呼び出されたAPIの違いにほかならない.
C++の勉強を始めると、cin/coutに詳しいに違いありません.この2つのオブジェクトは非常に明瞭な<>演算子を使用してI/Oを行い、その使用形式は以下の通りです.
このようにI/Oの利点を行う場合、演算子リロード機能を使用すると、オブジェクトの特定のタイプを区別することなく、一連のオブジェクトの読み書きを1つの文で完了できます.MFCはクラスCArchiveを提供し、演算子<>のリロードを実現し、前のcinとcoutの方式でファイルI/Oを行うことを望んでいる.CFIleクラスとの連携により,int/floatなどの単純なタイプのファイルの読み書きだけでなく,シーケンス化可能なオブジェクト(Serializable Objects,この概念は後述)のファイルの読み書きも実現した.
一般に、CArchiveを使用してオブジェクトを読み込む手順は次のとおりです.
CArchiveを使用してオブジェクトを書き込みます.
CFIleは、MFCクラスライブラリ内のすべてのファイルクラスのベースクラスです.すべてのMFCが提供するファイルI/O機能はこのクラスに関連している.多くの場合、CFIle::Write/WriteHugeを直接呼び出してファイルを書き、CFIle::Read/ReadHugeを呼び出してファイルを読むのが好きです.このようなファイルI/Oは、MFCを使用しないファイルI/Oとあまり変わらず、従来のANSI CのファイルI/Oともあまり変わらず、呼び出されたAPIの違いにほかならない.
C++の勉強を始めると、cin/coutに詳しいに違いありません.この2つのオブジェクトは非常に明瞭な<>演算子を使用してI/Oを行い、その使用形式は以下の通りです.
// 1
int i;
cin >> i;
//here do something to object i
cout << i;
このようにI/Oの利点を行う場合、演算子リロード機能を使用すると、オブジェクトの特定のタイプを区別することなく、一連のオブジェクトの読み書きを1つの文で完了できます.MFCはクラスCArchiveを提供し、演算子<>のリロードを実現し、前のcinとcoutの方式でファイルI/Oを行うことを望んでいる.CFIleクラスとの連携により,int/floatなどの単純なタイプのファイルの読み書きだけでなく,シーケンス化可能なオブジェクト(Serializable Objects,この概念は後述)のファイルの読み書きも実現した.
一般に、CArchiveを使用してオブジェクトを読み込む手順は次のとおりです.
// 2
//
CFile file;
CFileException fe;
//
if(!file.Open(filename,CFile::modeRead,&fe))
{
fe.ReportError();
return;
}
// CArchive
CArchive ar(&file,CArchive::load);
ar >> obj1>>obj2>>obj3...>>objn;
ar.Flush();
// ,
ar.Close();
file.Close();
CArchiveを使用してオブジェクトを書き込みます.
// 3
//
CFile file;
CFileException fe;
//
if(!file.Open(filename,CFile::modeWrite|CFile::modeCreate,&fe))
{
fe.ReportError();
return;
}
// CArchive
CArchive ar(&file,CArchive::load);
ar << obj1<
, , , 。 MFC / / , , , 。 CDocument CObject Serilize , 。
/ (ID_FILE_OPEN) ,CWinApp OnFileOpen , (MDI)/ (SDI) 、 , CDocument::OnOpenDocument ,CDocument::OnOpenDocument :
// 4
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
if (IsModified())
TRACE0("Warning: OnOpenDocument replaces an unsaved document./n");
CFileException fe;
CFile* pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
return FALSE;
}
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive); // load me
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
DeleteContents(); // remove failed contents
TRY
{
ReportSaveLoadException(lpszPathName, e,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // start off with unmodified
return TRUE;
}
に、ユーザがメニューファイル/ファイル (ID_FILE_SAVE)を するか、ファイル/ を けて するか…(ID_FILE_SAVEAS)の 、CWinApp::OnFileSaveとCWinApp::OnFileSaveAsが にCDocument::OnSaveDocumentを び し、この は のように されます.
// 5
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
CFileException fe;
CFile* pFile = NULL;
pFile = GetFile(lpszPathName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
TRUE, AFX_IDP_INVALID_FILENAME);
return FALSE;
}
CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
saveArchive.m_pDocument = this;
saveArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
Serialize(saveArchive); // save me
saveArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
TRY
{
ReportSaveLoadException(lpszPathName, e,
TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL
SetModifiedFlag(FALSE); // back to unmodified
return TRUE; // success
}
の2つのコードから、ファイルの み りと き みの は に じであり、 にはCObject::Serialize を び してドキュメント の み りと き みを していることがわかります( のsave meとload meを ).AppWizardで に されたMDIとSDIの 、システムはこの のリロード を に し、デフォルトの は のとおりです.
// 6
void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
VCに しい が、すべてのコードを で するのが きな (もちろん の も ありません)、 が したCDocument クラスもこのデフォルトのSerialize を する があります.そうしないと、システムはファイルの み き にCObject::Serializeを び すしかありません.この は もしません.もちろん、 のオブジェクトのファイルの /ロードも しません.もちろん、ユーザーはID_をキャプチャすることもできます.FILE_OPENなどのメニューは、 のファイルの み き を しますが、このようなコードは に わしくなり、 みにくくなります.
CMyDoc::Serialize に ります.この はarオブジェクトの により, ファイルを んでいるか いているかを する.AppWizardはあなたのドキュメントが をしているのか からないので、 のファイルの み きコードを しません.あなたのドキュメントに3つのオブジェクトがあるとしますm_Obj_a,m_Obj_b,m_Obj_c,では のコードは:
// 7
void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_Obj_a << m_Obj_b << m_Obj_c;
}
else
{
ar >> m_Obj_a >> m_Obj_b >> m_Obj_c;
}
}
シリアル オブジェクト(Serializable Object)
サンプルコード7でファイルI/Oを うための は、m_Obj_aなどのオブジェクトはシリアル なオブジェクトでなければならない.シリアル なオブジェクトの は のとおりです.このクラスはCObjectから している) クラスはSerialize を したこのクラスは にDECLARE_を しています.SERIALマクロ クラスの ファイルにIMPLEMENT_を SERIALマクロ このクラスにはパラメータを たない があり、またはパラメータを つ のすべてのパラメータがデフォルトのパラメータ を しています.
ここで、シリアル なオブジェクト には なタイプは まれておらず、 なタイプの 、CArchiveは に <>のリロードを するため、シリアル を して み きを うことができる.
CObjectクラスから
シリアル には、オブジェクトがCObjectから するか、または1つのCObjectの クラスから する があります.この は で,ほとんどのクラス(CStringを く)がCObjectから しているため,MFCクラスから されたクラスに してこの を たす. のデータクラスに して、そのベースクラスをCObjectとして してこの を たすことができます.
Serialize の
Serialize はオブジェクトが にデータを する であり、シリアル の である.その はCMyDoc::Serializeと に,CArchive::IsStoringとCArchive::IsLoadingを いて の を し,<>を してオブジェクトの と み りを う.
DECLARE_の SERIALマクロ
DECLARE_SERIALマクロにはDECLARE_が まれていますDYNAMICとDECLARE_DYNCREATE は、クラスのCRuntimeClass を し、デフォルトのoperator>>リロードを します.このマクロが すると,CArchiveはReadObjectとWriteObjectを してオブジェクトI/Oを い,あらかじめタイプを らずにファイルからオブジェクトを み ることができる.
IMPLEMENT_の SERIAL
DECLARE_SERIALマクロとIMPLEMENT_SERIALマクロはペアで する があります.そうしないとDECLARE_SERIALマクロで されたエンティティは できず、 に エラーが します.
デフォルトコンストラクタ
これはCRuntimeClass::CreateObjectのオブジェクトに する です.
な は、ReadObject/WriteObjectと を せずにSerialize のみでオブジェクトを み きする 、 のシリアル な は であり、Serialize を すればよい. のクラスでは、シリアル が されていない は、リロードされた operator<>を することで できます.
なグラフィック をサポートするジオメトリ 、 プログラムが であると します.ここでは, なグラフィックシステムの を するのではなく, オブジェクトの とロードのみを する.
ベースクラスCPicture
グラフィックオブジェクトはCPictureから し、このクラスはシリアル を しているが、 には コードは の りである. // picture.h
#if !defined(__PICTURE_H__)
#define __PICTURE_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
const int TYPE_UNKNOWN = -1;
class CPicture:public CObject
{
int m_nType;//
DECLARE_SERIAL(CPicture)
public:
CPicture(int m_nType=TYPE_UNKNOWN):m_nType(m_nType){};
int GetType()const {return m_nType;};
virtual void Draw(CDC * pDC);
void Serialize(CArchive & ar);
};
#endif
//cpp picture.cpp
#include "stdafx.h"
#include "picture.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void CPicture::Draw(CDC * pDC)
{
// ,
}
void CPicture::Serialize(CArchive & ar)
{
if(ar.IsLoading())
{
ar << m_nType;
}else{
ar >> m_nType;
}
}
:CRuntimeClassはこのオブジェクトをインスタンス する があるため、Draw には はありませんが、このクラスは な として されていません.
CDocument クラスでのオブジェクトの とファイルI/Oプロセス
を するため、CDocumentクラス クラスでは、MFCが するテンプレートクラスCPtrListを いてオブジェクトを する.オブジェクトは のように されます. protected:
CTypedPtrList m_listPictures;
CTypedPtrListもCPtrListもSerialize を していないため、ar<>m_ListPicturesはオブジェクトをシーケンス するため、CPictureDocのSerialize は のように する があります. void CTsDoc::Serialize(CArchive& ar)
{
POSITION pos;
if (ar.IsStoring())
{
// TODO: add storing code here
pos = m_listPictures.GetHeadPosition();
while(pos != NULL)
{
ar << m_listPictures.GetNext (pos);
}
}
else
{
// TODO: add loading code here
RemoveAll();
CPicture * pPicture;
do{
try
{
ar >> pPicture;
TRACE("Read Object %d/n",pPicture->GetType ());
m_listPictures.AddTail(pPicture);
}
catch(CException * e)
{
e->Delete ();
break;
}
}while(pPicture != NULL);
}
m_pCurrent = NULL;
SetModifiedFlag(FALSE);
}
クラスのシリアル の
ジオメトリプログラムは、 、 、 、 などのグラフィックをサポートし、クラスCLine、CRectangle、CTriangle、CEllipseで されます.クラスCLineを に、シリアル を する: CPictureから CLineは、CLineクラス に のメンバー を します: CPoint m_ptStart,m_ptEnd;
この の の には、 DECLARE_SERIAL(CLine)
というマクロが される. Serialize void CLine::Serialize(CArchive & ar)
{
CPicture::Serialize(ar);
if(ar.IsLoading())
{
ar>>m_ptStart.x>>m_ptStart.y>>m_ptEnd.x>>m_ptEnd.y;
}else{
ar<
を CPPファイルに IMPLEMENT_SERIAL(CLine,CPicture,TYPE_LINE);
を
このように されたCLineはシリアル を し、 のグラフィッククラスは に することができる.