• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            MyMSDN

            MyMSDN記錄開發(fā)新知道

            用文檔序列化來保存打開文件[理論聯(lián)系實(shí)際]

            文檔與序列化

            一、文檔的基本特征

            文檔類文件是從CDocument繼承而來的。

            The CDocument class provides the basic functionality for user-defined document classes. A document represents the unit of data that the user typically opens with the File Open command and saves with the File Save command.

            翻譯:文檔類提供用戶自定義文檔類的基本功能。一個(gè)文檔的打開命令和保存命令是數(shù)據(jù)單元特征。

            CDocument supports standard operations such as creating a document, loading it, and saving it. The framework manipulates documents using the interface defined by CDocument.

            翻譯:文檔類支持標(biāo)準(zhǔn)操作有:創(chuàng)建文檔,載入文檔,和保存。框架界面使用由文檔類定義的界面。

            An application can support more than one type of document; for example, an application might support both spreadsheets and text documents. Each type of document has an associated document template; the document template specifies what resources (for example, menu, icon, or accelerator table) are used for that type of document. Each document contains a pointer to its associated CDocTemplate object.

            翻譯:一個(gè)應(yīng)用程序可以支持多于一種類型的文檔;例如,一個(gè)應(yīng)用程序可能同時(shí)支持電子表格和普通文本文檔。每一種類型的文檔有一種關(guān)聯(lián)文檔模板;文檔模板指定了(例如,菜單,圖標(biāo),或者加速表格)使用這些類型的文檔。每個(gè)文檔包含一個(gè)指針指向關(guān)聯(lián)的模板對(duì)象。

            Users interact with a document through the CView object(s) associated with it. A view renders an image of the document in a frame window and interprets user input as operations on the document. A document can have multiple views associated with it. When the user opens a window on a document, the framework creates a view and attaches it to the document. The document template specifies what type of view and frame window are used to display each type of document.

            翻譯:用戶將一個(gè)文檔和一個(gè)視類對(duì)象想關(guān)聯(lián)起來。一個(gè)視類扮演一個(gè)嵌入在文檔框架內(nèi)的圖像,在文檔內(nèi)解釋用戶的輸入操作。一個(gè)文檔可以有多個(gè)視類與其關(guān)聯(lián)。當(dāng)用戶在一個(gè)文檔上打開一個(gè)窗體,框架創(chuàng)造一個(gè)視圖,把它放在文檔上。文檔模板指定適合于用戶文檔類型的相同類的視圖和框架窗口用來顯示用戶打開的文件。

            Documents are part of the framework's standard command routing and consequently receive commands from standard user-interface components (such as the File Save menu item). A document receives commands forwarded by the active view. If the document doesn't handle a given command, it forwards the command to the document template that manages it.

            翻譯:文檔是一個(gè)框架標(biāo)準(zhǔn)命令路由,因此從標(biāo)準(zhǔn)用戶界面組件(如文件保存菜單項(xiàng))接受命令。一個(gè)文檔由其活動(dòng)視圖迅速接受命令。如果該文檔沒有沒有響應(yīng)給出的命令,那么該命令將交由文檔模板來管理。

            When a document's data is modified, each of its views must reflect those modifications. CDocument provides the UpdateAllViews member function for you to notify the views of such changes, so the views can repaint themselves as necessary. The framework also prompts the user to save a modified file before closing it.

            翻譯:當(dāng)一個(gè)文檔數(shù)據(jù)發(fā)生改變,每一個(gè)它的視圖將隨即發(fā)生改變。文檔類提供更新所有視圖成員函數(shù)來通報(bào)每一個(gè)視圖的改變,因此視圖可以在必要的時(shí)候被重繪。框架也在關(guān)閉前迅速保存改動(dòng)文件。

            To implement documents in a typical application, you must do the following:

            l???????? Derive a class from CDocument for each type of document.

            l???????? Add member variables to store each document's data.

            l???????? Implement member functions for reading and modifying the document's data. The document's views are the most important users of these member functions.

            l???????? Override the CObject::Serialize member function in your document class to write and read the document's data to and from disk.

            翻譯:在一個(gè)典型類型的應(yīng)用程序中實(shí)現(xiàn)一個(gè)文檔,你必須按以下步驟:

            l???????? 為每一種類型的文檔從 CDocument 派生一個(gè)類

            l???????? 增加成員函數(shù)來存儲(chǔ)每一個(gè)文檔的數(shù)據(jù)

            l???????? 為讀寫文檔數(shù)據(jù)實(shí)現(xiàn)成員函數(shù)。文檔視圖類是這個(gè)成員函數(shù)最重要的使用者。

            l???????? 在你的文檔類重載 CObject::Serialize 成員函數(shù),來將文檔數(shù)據(jù)從磁盤讀寫。

            序列化:

            本文解釋 Microsoft 基礎(chǔ)類庫 (MFC) 中提供的序列化機(jī)制,該機(jī)制使對(duì)象可以在程序運(yùn)行之間保持。

            序列化是指將對(duì)象寫入永久性存儲(chǔ)媒體(如磁盤文件)或從其中讀取對(duì)象的進(jìn)程。 MFC 對(duì) CObject 類中的序列化提供內(nèi)置支持。因此,所有從 CObject 派生的類都可利用 CObject 的序列化協(xié)議。

            序列化的基本思想是對(duì)象應(yīng)能將其當(dāng)前狀態(tài)(通常由該對(duì)象的成員變量指示)寫入永久性存儲(chǔ)中。以后,通過從存儲(chǔ)中讀取對(duì)象狀態(tài)或反序列化對(duì)象狀態(tài),可以重新創(chuàng)建該對(duì)象。序列化處理序列化對(duì)象時(shí)使用的對(duì)象指針和對(duì)象循環(huán)引用的所有詳細(xì)資料。關(guān)鍵之處在于對(duì)象本身負(fù)責(zé)讀寫其自身狀態(tài)。因此,對(duì)于可序列化的類,必須實(shí)現(xiàn)基本的序列化操作。正如 序列化 文章組中所顯示的那樣,很容易將該功能添加到類中。

            MFC CArchive 類的對(duì)象用作將被序列化的對(duì)象和存儲(chǔ)媒體之間的中介物。該對(duì)象始終與 CFile 對(duì)象相關(guān)聯(lián),它從 CFile 對(duì)象獲得序列化所需的信息,包括文件名和請(qǐng)求的操作是讀取還是寫入。執(zhí)行序列化操作的對(duì)象可在不考慮存儲(chǔ)媒體本質(zhì)的情況下使用 CArchive 對(duì)象。

            CArchive 對(duì)象使用重載輸出運(yùn)算符 (<<) 和輸入運(yùn)算符 (>>) 來執(zhí)行讀寫操作。有關(guān)更多信息,請(qǐng)參見 序列化:序列化對(duì)象 文章中的 通過存檔存儲(chǔ)和加載 CObjects

            注意 ??? 請(qǐng)不要將 CArchive 類與通用 iostream 類混淆, iostream 類只用于格式化的文本。而 CArchive 類則用于二進(jìn)制格式的序列化對(duì)象。

            如果愿意,可以不使用 MFC 序列化而為永久性數(shù)據(jù)存儲(chǔ)創(chuàng)建自己的機(jī)制。您將需要在用戶的命令處重寫啟動(dòng)序列化的類成員函數(shù)。請(qǐng)參見 ID_FILE_OPEN ID_FILE_SAVE ID_FILE_SAVE_AS 標(biāo)準(zhǔn)命令的 技術(shù)說明 22 中的討論。

            下列文章介紹了序列化所需的兩個(gè)主要任務(wù):

            l???????? 序列化:創(chuàng)建可序列化的類

            l???????? 序列化:序列化對(duì)象

            序列化:序列化與數(shù)據(jù)庫輸入 /輸出的對(duì)比 一文描述了序列化在數(shù)據(jù)庫應(yīng)用程序中何時(shí)是適當(dāng)?shù)妮斎?/span> / 輸出技術(shù)。

            通過存檔存儲(chǔ)和加載 CObjects

            通過存檔存儲(chǔ)及加載 CObject 需要額外注意。在某些情況下,應(yīng)調(diào)用對(duì)象的 Serialize 函數(shù),其中, CArchive 對(duì)象是 Serialize 調(diào)用的參數(shù),與使用 CArchive “<<” “>>” 運(yùn)算符不同。要牢記的重要事實(shí)是: CArchive “>>” 運(yùn)算符基于由存檔先前寫到文件的 CRuntimeClass 信息構(gòu)造內(nèi)存中的 CObject

            因此,是使用 CArchive “<<” “>>” 運(yùn)算符還是調(diào)用 Serialize ,取決于是否需要加載存檔基于先前存儲(chǔ)的 CRuntimeClass 信息動(dòng)態(tài)地重新構(gòu)造對(duì)象。在下列情況下使用 Serialize 函數(shù):

            l???????? 反序列化對(duì)象時(shí),預(yù)先知道對(duì)象的確切的類。

            l???????? 反序列化對(duì)象時(shí),已為其分配了內(nèi)存。

            警告 ??? 如果使用 Serialize 函數(shù)加載對(duì)象,也必須使用 Serialize 函數(shù)存儲(chǔ)對(duì)象。不要使用 CArchive “<<” 運(yùn)算符先存儲(chǔ),然后使用 Serialize 函數(shù)進(jìn)行加載;或使用 Serialize 函數(shù)存儲(chǔ),然后使用 CArchive “>>” 運(yùn)算符進(jìn)行加載。

            以下示例闡釋了這些情況:

            class CMyObject : public CObject

            {

            // ...Member functions

            ?? public:

            ?? CMyObject() { }

            ?? virtual void Serialize( CArchive& ar ) { }

            ?

            // Implementation

            ?? protected:

            ?? DECLARE_SERIAL( CMyObject )

            };

            ?

            ?

            class COtherObject : public CObject

            {

            ?? // ...Member functions

            ?? public:

            ?? COtherObject() { }

            ?? virtual void Serialize( CArchive& ar ) { }

            ?

            // Implementation

            protected:

            ?? DECLARE_SERIAL( COtherObject )

            };

            ?

            ?

            class CCompoundObject : public CObject

            {

            ?? // ...Member functions

            ?? public:

            ?? CCompoundObject();

            ?? virtual void Serialize( CArchive& ar );

            ?

            // Implementation

            protected:

            ?? CMyObject m_myob;??? // Embedded object

            ?? COtherObject* m_pOther;??? // Object allocated in constructor

            ?? CObject* m_pObDyn;??? // Dynamically allocated object

            ?? //..Other member data and implementation

            ?

            ?? DECLARE_SERIAL( CCompoundObject )

            };

            ?

            IMPLEMENT_SERIAL(CMyObject,CObject,1)

            IMPLEMENT_SERIAL(COtherObject,CObject,1)

            IMPLEMENT_SERIAL(CCompoundObject,CObject,1)

            ?

            ?

            CCompoundObject::CCompoundObject()

            {

            ?? m_pOther = new COtherObject; // Exact type known and object already

            ??????????? //allocated.

            ?? m_pObDyn = NULL;??? // Will be allocated in another member function

            ??????????? // if needed, could be a derived class object.

            }

            ?

            void CCompoundObject::Serialize( CArchive& ar )

            {

            ?? CObject::Serialize( ar );??? // Always call base class Serialize.

            ?? m_myob.Serialize( ar );??? // Call Serialize on embedded member.

            ?? m_pOther->Serialize( ar );??? // Call Serialize on objects of known exact type.

            ?

            ?? // Serialize dynamic members and other raw data

            ?? if ( ar.IsStoring() )

            ?? {

            ????? ar << m_pObDyn;

            ????? // Store other members

            ?? }

            ?? else

            ?? {

            ????? ar >> m_pObDyn; // Polymorphic reconstruction of persistent

            ??????????? // object

            ??????????? //load other members

            ?? }

            }

            總之,如果可序列化的類將嵌入的 CObject 定義為成員,則不應(yīng)使用該對(duì)象的 CArchive “<<” “>>” 運(yùn)算符,而應(yīng)調(diào)用 Serialize 函數(shù)。同時(shí),如果可序列化的類將指向 CObject (或從 CObject 派生的對(duì)象)的指針定義為成員,但在自己的構(gòu)造函數(shù)中將其構(gòu)造為其他對(duì)象,則也應(yīng)調(diào)用 Serialize

            序列化:創(chuàng)建可序列化的類

            ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/vccore/html/_core_serialization.3a_.making_a_serializable_class.htm

            使類可序列化需要五個(gè)主要步驟。下面列出了這些步驟并在以后章節(jié)內(nèi)進(jìn)行了解釋:

            1. CObject 派生類 (或從 CObject 派生的某個(gè)類中派生)。
            2. 重寫 Serialize 成員函數(shù)
            3. 使用 DECLARE_SERIAL (在類聲明中)。
            4. 定義不帶參數(shù)的構(gòu)造函數(shù)
            5. 為類 在實(shí)現(xiàn)文件中使用 IMPLEMENT_SERIAL

            如果直接調(diào)用 Serialize而不是通過 CArchive“>>”“<<”運(yùn)算符調(diào)用,則序列化不需要最后三個(gè)步驟。

            CObject 派生類

            CObject 類中定義了基本的序列化協(xié)議和功能。正如在 CPerson 類的下列聲明中所示,通過從 CObject 中(或從 CObject 的派生類中)派生類,可獲得對(duì) CObject 的序列化協(xié)議及功能的訪問權(quán)限。

            ?

            重寫 Serialize 成員函數(shù)

            ?

            CObject 類中定義的 Serialize 成員函數(shù)實(shí)際上負(fù)責(zé)對(duì)捕獲對(duì)象的當(dāng)前狀態(tài)所必需的數(shù)據(jù)進(jìn)行序列化。 Serialize 函數(shù)具有 CArchive 參數(shù),該函數(shù)使用其來讀寫對(duì)象數(shù)據(jù)。 CArchive 對(duì)象具有成員函數(shù) IsStoring ,該成員函數(shù)指示 Serialize 正在存儲(chǔ)(即正在寫入數(shù)據(jù))還是正在加載(即正在讀取數(shù)據(jù))。用 IsStoring 的結(jié)果作為參考,使用輸出運(yùn)算符 (<<) 將對(duì)象數(shù)據(jù)插入到 CArchive 對(duì)象中或使用輸入運(yùn)算符 (>>) 提取數(shù)據(jù)。

            假定一個(gè)類是從 CObject 派生的并具有兩個(gè)新成員變量,分別為 CString WORD 類型。下列類聲明段顯示了新成員變量和重寫的 Serialize 成員函數(shù)的聲明:

            class CPerson : public CObject

            {

            public:

            ??? DECLARE_SERIAL( CPerson )

            ??? // empty constructor is necessary

            ??? CPerson(){};

            ?

            ??? CString m_name;

            ??? WORD?? m_number;

            ?

            ??? void Serialize( CArchive& archive );

            ???

            ??? // rest of class declaration

            };

            ?

            重寫 Serialize 成員函數(shù)

            1. 調(diào)用 Serialize 的基類版本以確保序列化對(duì)象的繼承部分。
            2. 插入或提取您的類所特定的成員變量。

            輸出運(yùn)算符及輸入運(yùn)算符與存檔類交互作用以讀寫數(shù)據(jù)。下面的示例顯示了如何實(shí)現(xiàn)以上聲明的 CPerson類的 Serialize

            				
            						
            void ?CPerson::Serialize(?CArchive & ?archive?)
            {
            ????
            // ?call?base?class?function?first
            ????
            // ?base?class?is?CObject?in?this?case
            ????CObject::Serialize(?archive?);

            ????
            // ?now?do?the?stuff?for?our?specific?class
            ???? if (?archive.IsStoring()?)
            ????????archive?
            << ?m_name? << ?m_number;
            ????
            else
            ????????archive?
            >> ?m_name? >> ?m_number;
            }

            也可使用 CArchive::ReadCArchive::Write成員函數(shù)來讀寫大量未鍵入的數(shù)據(jù)。

            使用 DECLARE_SERIAL

            在支持序列化的類的聲明中需要 DECLARE_SERIAL宏,如下所示:

            				
            class ?CPerson?:? public ?CObject
            {
            ????DECLARE_SERIAL(?CPerson?)
            ????
            // ?rest?of?declaration?follows
            }
            ;
            定義不帶參數(shù)的構(gòu)造函數(shù)

            反序列化對(duì)象(從磁盤上加載)后,MFC 重新創(chuàng)建這些對(duì)象時(shí),需要一個(gè)默認(rèn)的構(gòu)造函數(shù)。反序列化進(jìn)程將用重新創(chuàng)建對(duì)象所需的值填充所有成員變量。

            可將該構(gòu)造函數(shù)聲明為公共的、受保護(hù)的或私有的。如果使該構(gòu)造函數(shù)成為受保護(hù)的或私有的,請(qǐng)確保它將僅由序列化函數(shù)使用。該構(gòu)造函數(shù)必須使對(duì)象處于這樣一種狀態(tài):必要時(shí),可允許將其安全刪除。

            注意 ??? 如果忘記在使用 DECLARE_SERIAL IMPLEMENT_SERIAL 宏的類中定義不帶參數(shù)的構(gòu)造函數(shù),將在使用 IMPLEMENT_SERIAL 宏的行上得到 沒有可用的默認(rèn)構(gòu)造函數(shù) 編譯器警告。

            在實(shí)現(xiàn)文件中使用 IMPLEMENT_SERIAL

            IMPLEMENT_SERIAL 宏用于定義從 CObject中派生可序列化類時(shí)所需的各種函數(shù)。在類的實(shí)現(xiàn)文件 (.CPP) 中使用這個(gè)宏。該宏的前兩個(gè)參數(shù)是類名和直接基類的名稱。

            該宏的第三個(gè)參數(shù)是架構(gòu)編號(hào)。架構(gòu)編號(hào)實(shí)質(zhì)上是類對(duì)象的版本號(hào)。架構(gòu)編號(hào)使用大于或等于零的整數(shù)。(請(qǐng)不要將該架構(gòu)編號(hào)與數(shù)據(jù)庫術(shù)語混淆。)

            MFC 序列化代碼在將對(duì)象讀取到內(nèi)存時(shí)檢查該架構(gòu)編號(hào)。如果磁盤上對(duì)象的架構(gòu)編號(hào)與內(nèi)存中類的架構(gòu)編號(hào)不匹配,庫將引發(fā) CArchiveException,防止程序讀取對(duì)象的不正確版本。

            如果要使 Serialize成員函數(shù)能夠讀取多個(gè)版本(即,讀取用應(yīng)用程序的不同版本寫入的文件),可將 VERSIONABLE_SCHEMA值作為 IMPLEMENT_SERIAL宏的參數(shù)。有關(guān)用法信息和示例,請(qǐng)參見 CArchive類的 GetObjectSchema成員函數(shù)。

            以下示例顯示了如何將 IMPLEMENT_SERIAL用于從 CObject派生的 CPerson類。

            				
            						IMPLEMENT_SERIAL( CPerson, CObject, 1 )
            				
            		

            正如序列化:序列化對(duì)象文章中所討論的,一旦具有可序列化的類,就可以序列化類的對(duì)象。

            序列化 :序列化對(duì)象

            序列化:創(chuàng)建可序列化的類 一文說明如何使類可序列化。一旦具有可序列化的類,就可以通過 CArchive對(duì)象將該類的對(duì)象序列化到文件和從文件序列化該類的對(duì)象。本文將解釋:

            可使框架創(chuàng)建可序列化文檔的存檔或自己顯式創(chuàng)建 CArchive對(duì)象。通過使用 CArchive“<<”“>>”運(yùn)算符或在某些情況下通過調(diào)用 CObject派生類的 Serialize 函數(shù),可在文件和可序列化對(duì)象間傳輸數(shù)據(jù)。

            什么是Archive對(duì)象?

            CArchive 對(duì)象提供了一個(gè)類型安全緩沖機(jī)制,用于將可序列化對(duì)象寫入 CFile對(duì)象或從中讀取可序列化對(duì)象。通常,CFile對(duì)象表示磁盤文件;但是,它也可以是表示剪貼板的內(nèi)存文件(CSharedFile對(duì)象)。

            給定的 CArchive對(duì)象要么存儲(chǔ)數(shù)據(jù)(即寫入數(shù)據(jù)或?qū)?shù)據(jù)序列化),要么加載數(shù)據(jù)(即讀取數(shù)據(jù)或?qū)?shù)據(jù)反序列化),但決不能同時(shí)進(jìn)行。CArchive對(duì)象的壽命只限于將對(duì)象寫入文件或從文件讀取對(duì)象的一次傳遞。因此,需要兩個(gè)連續(xù)創(chuàng)建的 CArchive對(duì)象將數(shù)據(jù)序列化到文件,然后從文件反序列化數(shù)據(jù)。

            當(dāng)存檔將對(duì)象存儲(chǔ)到文件時(shí),存檔將 CRuntimeClass名稱附加到這些對(duì)象。然后,當(dāng)另一個(gè)存檔將對(duì)象從文件加載到內(nèi)存時(shí),將基于這些對(duì)象的 CRuntimeClass動(dòng)態(tài)地重新構(gòu)造 CObject派生的對(duì)象。通過存儲(chǔ)存檔將給定對(duì)象寫入文件時(shí),該對(duì)象可能被引用多次。然而,加載存檔將僅對(duì)該對(duì)象重新構(gòu)造一次。有關(guān)存檔如何將 CRuntimeClass信息附加到對(duì)象以及重新構(gòu)造對(duì)象(考慮可能的多次引用)的詳細(xì)信息,請(qǐng)參見技術(shù)說明 2

            將數(shù)據(jù)序列化到存檔時(shí),存檔積累數(shù)據(jù),直到其緩沖區(qū)被填滿為止。然后,存檔將其緩沖區(qū)寫入 CArchive對(duì)象指向的 CFile對(duì)象。同樣,當(dāng)您從存檔中讀取數(shù)據(jù)時(shí),存檔會(huì)將數(shù)據(jù)從文件讀取到它的緩沖區(qū),然后從緩沖區(qū)讀取到反序列化的對(duì)象。這種緩沖減少了物理讀取硬盤的次數(shù),從而提高了應(yīng)用程序的性能。

            創(chuàng)建 CArchive 對(duì)象有兩種方法:

            l???????? 通過框架隱式創(chuàng)建 CArchive 對(duì)象

            l???????? 顯式創(chuàng)建 CArchive 對(duì)象

            通過框架隱式創(chuàng)建 CArchive 對(duì)象

            最普通且最容易的方法是使框架代表“文件”菜單上的“保存”、“另存為”和“打開”命令為文檔創(chuàng)建 CArchive 對(duì)象。

            以下是應(yīng)用程序的用戶從“文件”菜單上發(fā)出“另存為”命令時(shí),框架所執(zhí)行的操作:

            顯示“另存為”對(duì)話框并從用戶獲取文件名。

            打開用戶命名的文件作為 CFile 對(duì)象。

            創(chuàng)建指向該 CFile 對(duì)象的 CArchive 對(duì)象。在創(chuàng)建 CArchive 對(duì)象時(shí),框架將模式設(shè)置為“存儲(chǔ)”(即寫入或序列化),而不是“加載”(即讀取或反序列化)。

            調(diào)用在 CDocument 派生類中定義的 Serialize 函數(shù),將 CArchive 對(duì)象的引用傳遞給該函數(shù)。

            然后,文檔的 Serialize 函數(shù)將數(shù)據(jù)寫入 CArchive 對(duì)象(剛作了解釋)。從 Serialize 函數(shù)返回時(shí),框架先銷毀 CArchive 對(duì)象,再銷毀 CFile 對(duì)象。

            因此,如果讓框架為文檔創(chuàng)建 CArchive 對(duì)象,您所要做的一切是實(shí)現(xiàn)寫入存檔和從存檔中讀取的文檔的 Serialize 函數(shù)。您還必須為文檔的 Serialize 函數(shù)直接或間接依次序列化的任何 CObject 派生對(duì)象實(shí)現(xiàn) Serialize

            顯式創(chuàng)建 CArchive 對(duì)象

            除了通過框架將文檔序列化之外,在其他場(chǎng)合也可能需要 CArchive 對(duì)象。例如,可能要序列化到達(dá)或來自剪貼板的數(shù)據(jù),由 CSharedFile 對(duì)象表示。或者,可能要使用用戶界面來保存與框架提供的文件不同的文件。在這種情況下,可以顯式創(chuàng)建 CArchive 對(duì)象。使用下列過程,用與框架采用的相同方式來執(zhí)行此操作。

            顯式創(chuàng)建 CArchive 對(duì)象

            構(gòu)造 CFile 對(duì)象或從 CFile 導(dǎo)出的對(duì)象。

            按照下面示例所示,將 CFile 對(duì)象傳遞到 CArchive 的構(gòu)造函數(shù):

            CFile theFile;

            theFile.Open(..., CFile::modeWrite);

            CArchive archive(&theFile, CArchive::store);

            CArchive 構(gòu)造函數(shù)的第二個(gè)參數(shù)是指定存檔將用于向文件中存儲(chǔ)數(shù)據(jù)還是用于從文件中加載數(shù)據(jù)的枚舉值。對(duì)象的 Serialize 函數(shù)通過調(diào)用存檔對(duì)象的 IsStoring 函數(shù)來檢查該狀態(tài)。

            當(dāng)完成向 CArchive 對(duì)象存儲(chǔ)數(shù)據(jù)或從該對(duì)象中加載數(shù)據(jù)時(shí),關(guān)閉該對(duì)象。雖然 CArchive 對(duì)象(和 CFile 對(duì)象)會(huì)自動(dòng)關(guān)閉存檔(和文件),好的做法是顯式執(zhí)行,因?yàn)檫@使從錯(cuò)誤恢復(fù)更為容易。有關(guān)錯(cuò)誤處理的更多信息,請(qǐng)參見異常:捕捉和刪除異常一文。

            關(guān)閉 CArchive 對(duì)象

            以下示例闡釋了如何關(guān)閉 CArchive 對(duì)象:

            archive.Close();

            theFile.Close();

            ?

            使用 CArchive 對(duì)象的“ << ”和“ >> ”操作符

            CArchive 提供“ << ”和“ >> ”運(yùn)算符,用于向文件中寫入簡(jiǎn)單的數(shù)據(jù)類型和 CObjects 以及從文件中讀取它們。

            通過存檔將對(duì)象存儲(chǔ)在文件中

            以下示例顯示了如何通過存檔將對(duì)象存儲(chǔ)在文件中:

            CArchive ar(&theFile, CArchive::store);

            WORD wEmployeeID;

            ...

            ar << wEmployeeID;

            從先前存儲(chǔ)在文件中的值加載對(duì)象

            以下示例顯示了如何從先前存儲(chǔ)在文件中的值加載對(duì)象:

            CArchive ar(&theFile, CArchive::load);

            WORD wEmployeeID;

            ...

            ar >> wEmployeeID;

            通常,通過 CObject 派生類的 Serialize 函數(shù)中的存檔將數(shù)據(jù)存儲(chǔ)到文件中或從文件中加載數(shù)據(jù),必須已用 DECLARE_SERIALIZE 宏來聲明這些函數(shù)。將 CArchive 對(duì)象的引用傳遞到 Serialize 函數(shù)。調(diào)用 CArchive 對(duì)象的 IsLoading 函數(shù)以確定是否已調(diào)用 Serialize 函數(shù)來從文件中加載數(shù)據(jù)或?qū)?shù)據(jù)存儲(chǔ)到文件中。

            可序列化的 CObject 派生類的 Serialize 函數(shù)通常具有以下形式:

            void CPerson::Serialize(CArchive& ar)

            {

            ??? CObject::Serialize(ar);

            ??? if (ar.IsStoring())

            ??? {

            ??????? // TODO:? add storing code here

            ??? }

            ??? else

            ??? {

            ??? // TODO:? add loading code here

            ??? }

            }

            上面的代碼模板與 AppWizard 為該文檔(從 CDocument 派生的類)的 Serialize 函數(shù)所創(chuàng)建的代碼模板完全相同。由于存儲(chǔ)代碼和加載代碼總是并行,該代碼模板有助于寫的代碼更容易復(fù)查,如下例中所示:

            void CPerson:Serialize(CArchive& ar)

            {

            ??? if (ar.IsStoring())

            ??? {

            ??????? ar << m_strName;

            ??????? ar << m_wAge;

            ??? }

            ??? else

            ??? {

            ??????? ar >> m_strName;

            ??????? ar >> m_wAge;

            ??? }

            }

            庫將 CArchive 的“ << ”和“ >> ”運(yùn)算符定義為第一操作數(shù),將下列數(shù)據(jù)類型和類類型定義為第二操作數(shù):

            CObject*

            SIZE CSize

            float

            WORD

            CString

            POINT CPoint

            DWORD

            BYTE

            RECT CRect

            double

            LONG

            CTime CTimeSpan

            int

            COleCurrency

            COleVariant

            COleDateTime

            COleDateTimeSpan

            ?

            ?

            注意 ?? 通過存檔存儲(chǔ)及加載 CObjects 需要額外注意。有關(guān)更多信息,請(qǐng)參見通過存檔存儲(chǔ)和加載 CObjects

            CArchive 的“ << ”和“ >> ”運(yùn)算符總是返回 CArchive 對(duì)象的引用,該引用為第一操作數(shù)。這使您可以鏈接運(yùn)算符,如下所示:

            BYTE bSomeByte;

            WORD wSomeWord;

            DWORD wSomeDoubleWord;

            ...

            ar << bSomeByte << wSomeWord << wSomeDoubleWord;

            ?

            ?

            通過存檔存儲(chǔ)及加載 CObject (見前)

            下面用一個(gè)示例來解釋這個(gè)問題。

            目標(biāo):一個(gè)畫圖程序,通過保存打開按鈕存取圖片。方法:保存圖片繪制信息。

            按步驟:

            l???????? 創(chuàng)建可序列化的類 ->Graph.cpp+Graph.h

            l???????? View 類中添加對(duì)控件的響應(yīng),實(shí)現(xiàn)畫圖功能,每次鼠標(biāo)彈起的時(shí)候保存繪圖信息

            l???????? 保存文件(通過 Doc Serialize 來保存數(shù)據(jù))

            l???????? 打開文件(通過 Doc Serialize 來讀取數(shù)據(jù),并將其重繪)

            View 類中定義 CObArray m_obArray;

            下面按這個(gè)思路來完成:(在 C Graph 子類中完成重繪的畫圖功能)

            Graph.cpp

            #include "StdAfx.h"

            #include ".\graph.h"

            IMPLEMENT_SERIAL(CGraph, CObject, 1 )

            CGraph::CGraph(void)

            : m_ptOrigin(0)

            , m_ptEnd(0)

            , m_nDrawType(0)

            {

            }

            CGraph::CGraph(CPoint m_ptOrigin,CPoint m_ptEnd,UINT m_nDrawType)

            {

            ???? this->m_ptOrigin=m_ptOrigin;

            ???? this->m_ptEnd=m_ptEnd;

            ???? this->m_nDrawType=m_nDrawType;

            }

            CGraph::~CGraph(void)

            {

            }

            void CGraph::Serialize( CArchive& ar )

            {

            ???? // 繼承基類的CObject

            ??? CObject::Serialize( ar );

            ??? if( ar.IsStoring() )

            ???? {

            ??????? ar << m_ptOrigin << m_ptEnd << m_nDrawType ;

            ???? }

            ???? else

            ???? {

            ???????? ar >> m_ptOrigin >> m_ptEnd >> m_nDrawType ;

            ???? }

            }

            void CGraph::Draw(CDC* pDC)

            {

            ???? CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));

            ???? CBrush *pOldBrush=pDC->SelectObject(pBrush);

            ???? switch(m_nDrawType)

            ???? {

            ???? case 1:

            ???????? pDC->SetPixel(m_ptEnd,RGB(0,0,0));

            ???????? break;

            ???? case 2:

            ???????? pDC->MoveTo(m_ptOrigin);

            ???????? pDC->LineTo(m_ptEnd);

            ???????? break;

            ???? case 3:

            ???????? pDC->Rectangle(CRect(m_ptOrigin,m_ptEnd));

            ???????? break;

            ???? case 4:

            ???????? pDC->Ellipse(CRect(m_ptOrigin,m_ptEnd));

            ???????? break;

            ???? }

            ???? pDC->SelectObject(pOldBrush);

            }

            Graph..h

            #pragma once

            #include "atltypes.h"

            ?

            class CGraph : publicCObject

            {

            public :

            ???? DECLARE_SERIAL( CGraph )

            ???? CGraph(void);

            ???? CGraph::CGraph(CPoint m_ptOrigin,CPoint m_ptEnd,UINT m_nDrawType);

            ???? void Serialize( CArchive& ar );

            ???? ~CGraph(void);

            ???? CPoint m_ptOrigin;

            ???? CPoint m_ptEnd;

            ???? UINT m_nDrawType;

            ???? void Draw(CDC* pDC);

            };

            View 類中添加畫圖功能

            void CGraphicSerialView::OnDot()

            {

            ???? // TODO: 在此添加命令處理程序代碼

            ???? m_nDrawType=1;

            }

            ?

            void CGraphicSerialView::OnLine()

            {

            ???? // TODO: 在此添加命令處理程序代碼

            ???? m_nDrawType=2;

            }

            ?

            void CGraphicSerialView::OnRectangle()

            {

            ???? // TODO: 在此添加命令處理程序代碼

            ???? m_nDrawType=3;

            }

            ?

            void CGraphicSerialView::OnEllipse()

            {

            ???? // TODO: 在此添加命令處理程序代碼

            ???? m_nDrawType=4;

            }

            ?

            void CGraphicSerialView::OnLButtonDown(UINT nFlags, CPoint point)

            {

            ???? // TODO: 在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值

            ???? m_ptOrigin = point;

            ???? CView::OnLButtonDown(nFlags, point);

            }

            ?

            void CGraphicSerialView::OnLButtonUp(UINT nFlags, CPoint point)

            {

            ???? // TODO: 在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值

            ???? CClientDC dc(this);

            ???? CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));???? // 選擇一個(gè)透明畫刷

            ???? dc.SelectObject(pBrush);

            ?

            ???? switch(m_nDrawType)

            ???? {

            ???? case 1:

            ???????? dc.SetPixel(point,RGB(0,0,0));

            ???????? break;

            ???? case 2:

            ???????? dc.MoveTo(m_ptOrigin);

            ???????? dc.LineTo(point);

            ???????? break;

            ???? case 3:

            ???????? dc.Rectangle(m_ptOrigin.x,m_ptOrigin.y,point.x,point.y);

            ???????? break;

            ???? case 4:

            ???????? dc.Ellipse(CRect(m_ptOrigin,point));

            ???????? break;

            ???? default:

            ???????? break;

            ???? }

            ???? // 將圖形信息保存起來

            ???? CGraph *pGraph=new CGraph( m_ptOrigin , point , m_nDrawType );?? // 創(chuàng)建一個(gè)pGraph指針指向一個(gè)存儲(chǔ)圖形信息的“圖形”

            ???? m_obArray.Add(pGraph);// 將一群這樣的pGraph組織在一起放進(jìn)m_obArray

            ???? CView::OnLButtonUp(nFlags, point);

            }

            但是要保存和讀取文件需要用到 Serialize

            因此轉(zhuǎn)到 Doc

            void CGraphicSerialDoc::Serialize(CArchive& ar)

            {

            ???? POSITION pos=GetFirstViewPosition();// 獲得第一個(gè)視類對(duì)象在對(duì)象列表中的位置

            ???? CGraphicSerialView *pView=(CGraphicSerialView*)GetNextView(pos);// 找到當(dāng)前視類對(duì)象的指針,由于這是單文檔,因此只有一個(gè)視類對(duì)象

            ???? if (ar.IsStoring())

            ???? {

            ???????? // TODO: 在此添加存儲(chǔ)代碼

            ???????? int nCount=pView->m_obArray.GetSize();

            ???????? ar<<nCount;?? // 為了在讀取文件的時(shí)候能夠知道元素個(gè)數(shù),因此在保存的時(shí)候把個(gè)數(shù)也存進(jìn)去

            ???????? for(int i=0;i<nCount;i++)

            ???????? {

            ????????????? ar<<pView->m_obArray.GetAt(i);

            ???????? }

            ???? }

            ???? else

            ???? {

            ???????? // TODO: 在此添加加載代碼

            ???????? int nCount;

            ???????? ar>>nCount;

            ???????? CGraph *pGraph;

            ???????? for(int i=0;i<nCount;i++)

            ???????? {

            ????????????? ar>>pGraph;

            ????????????? pView->m_obArray.Add(pGraph);

            ???????? }

            ???? }

            }

            但是讀取數(shù)據(jù)的時(shí)候還需要重繪圖像:轉(zhuǎn)回View類,因?yàn)樵?span lang="EN-US">View類加載的時(shí)候會(huì)自動(dòng)調(diào)用OnDraw(),OnDraw()中添加如下語句。

            ???? int nCount;

            ???? nCount=m_obArray.GetSize();

            ???? for(int i=0;i<nCount;i++)

            ???? {

            ???????? ((CGraph*)m_obArray.GetAt(i))->Draw(pDC);

            ???? }

            基本上完成了通過serialize保存和打開文件。

            serialize的好處:通過緩存來保存,當(dāng)緩存區(qū)滿了才進(jìn)行一次讀/寫,因此提高了應(yīng)用程序的效率

            ?

            另外 Archive 對(duì)象是支持序列化的,因此在讀寫數(shù)據(jù)的時(shí)候即可以按以上方法在 Doc 類的 Serialize 來保存和打開數(shù)據(jù)。

            因此修改 Doc 中的 Serialize

            void CGraphicSerialDoc::Serialize(CArchive& ar)

            {

            ???? POSITION pos=GetFirstViewPosition();// 獲得第一個(gè)視類對(duì)象在對(duì)象列表中的位置

            ???? CGraphicSerialView *pView=(CGraphicSerialView*)GetNextView(pos);// 找到當(dāng)前視類對(duì)象的指針,由于這是單文檔,因此只有一個(gè)視類對(duì)象

            ???? if (ar.IsStoring())

            ???? {

            ???????? // TODO: 在此添加存儲(chǔ)代碼

            ???? }

            ???? else

            ???? {

            ???????? // TODO: 在此添加加載代碼

            ???? }

            ???? pView->m_obArray.Serialize(ar);? // 將這個(gè)數(shù)據(jù)傳遞給

            }

            其中CObArray類對(duì)象讀取數(shù)據(jù)的方法:(以下是MFC源代碼,無須用戶添加)

            void CObArray::Serialize(CArchive& ar)

            {

            ???? ASSERT_VALID(this);

            ?

            ???? CObject::Serialize(ar);

            ?

            ???? if (ar.IsStoring())

            ???? {

            ???????? ar.WriteCount(m_nSize);

            ???????? for (INT_PTR i = 0; i < m_nSize; i++)

            ????????????? ar << m_pData[i];

            ???? }

            ???? else

            ???? {

            ???????? DWORD_PTR nOldSize = ar.ReadCount();

            ???????? SetSize(nOldSize);

            ???????? for (INT_PTR i = 0; i < m_nSize; i++)

            ????????????? ar >> m_pData[i];

            ???? }

            }

            ?

            下面直接在 Doc 類中使用 CObArray 對(duì)象(取消之前定義在 View 類中的該類對(duì)象)

            Doc 類中定義 CObArray m_obArray;

            存圖形數(shù)據(jù)的代碼修改為:

            ???? CGraphicDoc *pDoc=GetDocument();// 通過視類提供的GetDocument()方法來獲得Doc類指針

            ???? pDoc->m_obArray.Add(pGraph);

            修改其他位置的 m_obArray

            void CGraphicSerialView::OnDraw(CDC* pDC)

            {

            ???? ……

            ???? nCount=pDoc->m_obArray.GetSize();

            ???? for(int i=0;i<nCount;i++)

            ???? {

            ???? ???? ((CGraph*)pDoc->m_obArray.GetAt(i))->Draw(pDC);???//Doc類中定義m_obArray的情況

            ???? }

            }

            void CGraphicSerialDoc::Serialize(CArchive& ar)

            {

            ……

            ???? m_obArray.Serialize(ar); ??? //Doc 類中定義m_obArray的情況

            }

            當(dāng)我們新建和打開文檔的時(shí)候,我們之前的文檔對(duì)象并沒有被銷毀(系統(tǒng)利用 OnNewDocument 方法所新建的對(duì)象)之前在堆上建立了文檔對(duì)象。此時(shí)應(yīng)刪除文檔對(duì)象。

            在文檔類中重載函數(shù) void CGraphicSerialDoc::DeleteContents() 來刪除文檔對(duì)象,以避免內(nèi)存泄露。

            void CGraphicSerialDoc::DeleteContents()

            {

            ???? int nCount;

            ???? nCount=m_obArray.GetSize();

            ???? /*for(int i=0;i<nCount;i++)

            ???? {

            ???????? delete m_obArray.GetAt(i);

            ???????? //m_obArray.RemoveAt(i);

            ???? }

            ???? m_obArray.RemoveAll();*/

            ???? while(nCount--)

            ???? {

            ???????? delete m_obArray.GetAt(nCount);

            ???????? m_obArray.RemoveAt(nCount);

            ???? }

            ???? CDocument::DeleteContents();

            }

            下面是關(guān)于內(nèi)存泄露的在此的一段論述。(此文同時(shí)發(fā)布于)

            http://m.shnenglu.com/mymsdn/archive/2006/08/16/11266.html

            posted on 2006-08-16 23:19 volnet 閱讀(2433) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            特殊功能
             
            国产精品99久久久精品无码| 思思久久99热只有频精品66| 久久久久久久久久久精品尤物| 伊人久久无码精品中文字幕| 久久久久久久女国产乱让韩| 东方aⅴ免费观看久久av| 久久久久久国产精品无码超碰| 久久久中文字幕| 国内精品久久久久影院薰衣草| 久久久久99精品成人片直播| 99久久国产亚洲高清观看2024 | 亚洲va久久久噜噜噜久久狠狠 | 伊人久久一区二区三区无码| 久久久久久久人妻无码中文字幕爆 | 伊人久久大香线蕉AV一区二区| 久久AV高清无码| 亚洲AV乱码久久精品蜜桃| 66精品综合久久久久久久| 国色天香久久久久久久小说| 久久亚洲国产欧洲精品一| 东方aⅴ免费观看久久av| 精品久久久无码中文字幕| 国产一区二区三区久久精品| 亚洲中文字幕无码一久久区| 国产成人精品久久亚洲| 久久精品国产99国产精品澳门| 精品久久久久久中文字幕大豆网| 国产精品九九久久精品女同亚洲欧美日韩综合区 | 奇米影视7777久久精品人人爽| 国产—久久香蕉国产线看观看| 久久国产色AV免费观看| 日韩人妻无码精品久久免费一 | 亚洲精品无码久久千人斩| 四虎国产精品免费久久| 久久噜噜久久久精品66| 思思久久好好热精品国产| 久久有码中文字幕| 日本国产精品久久| 久久人与动人物a级毛片| 久久热这里只有精品在线观看| 伊人久久大香线蕉无码麻豆|