📄 ch08.htm
字号:
<HTML>
<HEAD>
<TITLE>Special Edition Using Visual C++ 5 - Chapter 8</TITLE>
<LINK REL="Next" HREF="ch09.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/ch09.htm">
<LINK REL="Previous" HREF="ch07.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/ch07.htm"></HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H2><B>Chapter 8</B></H2>
<H2><A ID="I1" NAME="I1"><B>Persistence and File I/O</B></A></H2>
<hr>
<ul>
<li> <B>How persistent objects help you keep documents up-to-date</B></P>
<P> Because persistent objects know how to save and load their own data, they're perfect for dealing with documents that contain custom data types.</P>
<li> <B>How a standard document/view application deals with persistence</B></P>
<P> When you create an application with AppWizard, you get a default version of a persistent object in the form of the document class.</P>
<li> <B>How to create your own persistent class</B></P>
<P> Creating a custom persistent class requires completing several programming steps, but it's easy when you know the tricks.</P>
<li> <B>How to use MFC's </B><B><font color="#008000">CFile</font></B><B> class to read and write files directly</B></P>
<P> You don't need persistent objects to deal with file I/O. You can handle files the old-fashioned way if you like.</P>
<li> <B>How to create your own archive objects</B></P>
<P> Objects of the <font color="#008000">CArchive</font> class are the heart of persistent objects. Once you understand the <font color="#008000">CFile</font> class, you're ready to create <font color="#008000">CArchive</font> objects, too.</P>
</ul>
<P>One of the most important things a program must do is save a user's data after that data has been changed in some way. Without the capability to save edited data, the work the user performs with an application exists only as long as the application is
running, vanishing the instant the user exits the application. Not a good way to get work done! In many cases, especially when using AppWizard to create an application, Visual C++ provides much of the code you need to save and load data. However, in some
cases—most notably when you create your own object types—you have to do a little extra work to keep your user's files up-to-date.</P>
<H3><A ID="I2" NAME="I2"><B>Objects and Persistence</B></A></H3>
<P>When you're writing an application, you deal with a lot of different types of objects. Some of your data objects might be simple types like integers and characters. Other objects might be instances of classes, like strings from the <font
color="#008000">CString</font> class or even objects created from your own custom classes. When using objects in applications that must create, save, and load documents, you need a way to save and load the state of those objects so that you can recreate
them exactly as the user left them at the end of the last session.</P>
<P>An object's capability to save and load its state is called <I>persistence</I>. Almost all of the MFC classes are persistent because they are derived either directly or indirectly from MFC's <font color="#008000">CObject</font> class, which provides
the basic functionality for saving and loading an object's state. In the following section you get a review of how MFC makes a document object persistent.</P>
<H3><A ID="I3" NAME="I3"><B>The File Demo Application</B></A></H3>
<P>When you create a program using Visual C++'s AppWizard, you get an application that uses document and view classes to organize, edit, and display its data. As discussed in <A HREF="index05.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index05.htm" target="text">Chapter 5</A>, "Documents and
Views," the document object, which is derived from the <font color="#008000">CDocument</font> class, is responsible for holding the application's data during a session and for saving and loading the data so that the document persists from one session
to another.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P>In the <font color="#008000">CHAP9\FILE</font> folder of this book's CD-ROM, you'll find the File Demo application, which demonstrates the basic techniques behind saving and loading data of an object derived from <font color="#008000">CDocument</font>.
When you run the application, you see the window shown in Figure 8.1. This window displays the contents of the current document. In this case, a document is a single string containing a short message.</P>
<A HREF="Jfigs01.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch08/Jfigs01.gif"><b>Fig. 8.1</b></A>
<P><I>The File Demo application demonstrates basic document persistence.</I></P>
<P>When the program first begins, the message is automatically set to the string "Default Message." However, you can change this message to anything you like. To do this, select the <U>E</U>dit, <U>C</U>hange Message command. You then see the
dialog box shown in Figure 8.2. Type a new message in the edit box and click the OK button. The new message appears in the window.</P>
<A HREF="Jfigs02.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch08/Jfigs02.gif"><b>Fig. 8.2</b></A>
<P><I>You can use the Change Message dialog box to edit the application's message string.</I></P>
<P>If you choose to exit the program, the document's current state is lost. The next time you run the program, you again have to change the message string. To avoid this complication, you can save the document before exiting the program. Choose the
<U>F</U>ile, <U>S</U>ave command to do this (see Figure 8.3). After saving the document, you can reload it at any time by choosing <U>F</U>ile, <U>O</U>pen.</P>
<A HREF="Jfigs03.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch08/Jfigs03.gif"><b>Fig. 8.3</b></A>
<P><I>Use the </I><I><U>F</U></I><I>ile menu to save and load documents.</I></P>
<P><A ID="I4" NAME="I4"><B>A Review of Document Classes</B></A></P>
<P>What you've just experienced, saving and opening files, is object persistence from the user's point of view. The programmer, of course, needs to know much more about how persistence works. Although you had some experience with document classes in <A
HREF="index05.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index05.htm" target="text">Chapter 5</A>, "Documents and Views," you'll now review the basic concepts with an eye towards extending those concepts to your own custom classes.</P>
<P>When working with an application created by AppWizard, there are several steps you must complete to enable your document to save and load its state. Those steps, as they apply to an SDI (Single Document Interface) application, will be discussed in this
section. The steps are as follows:</P>
<ol>
<li><P> Define the member variables that will hold the document's data.</P>
<li><P> Initialize the member variables in the document class's <font color="#008000">OnNewDocument()</font> member function.</P>
<li><P> Display the current document in the view class's <font color="#008000">OnDraw()</font> member function.</P>
<li><P> Provide member functions in the view class that enable the user to edit the document.</P>
<li><P> Add, to the document class's <font color="#008000">Serialize()</font> member function, the code needed to save and load the data that comprises the document.</P>
</ol>
<P>You will see these new member variables, and the way that OnDraw() and Serialize use them, in the samples in this chapter.</P>
<P><A ID="I5" NAME="I5"><B>A Quick Look at File Demo's Source Code</B></A></P>
<P>In the File Demo application, the document class declares its document storage in its header file (<font color="#008000">FILEDOC.H</font>), like this:</P>
<pre><font color="#008000">// Attributes</font></pre>
<pre><font color="#008000">public:</font></pre>
<pre><font color="#008000"> CString m_message;</font></pre>
<P>In this case, the document's storage is nothing more than a single string object. Usually, your document's storage needs are much more complex. This single string, however, is enough to demonstrate the basics of a persistent document.</P>
<P>The document class also must initialize the document's data, which it does in the <font color="#008000">OnNewDocument()</font> member function, as shown in Listing 8.1.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 8.1—</I>FILEDOC.CPP<I>—Initializing the Document's Data</I></P>
<pre><font color="#008000">BOOL CFileDoc::OnNewDocument()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> if (!CDocument::OnNewDocument())</font></pre>
<pre><font color="#008000"> return FALSE;</font></pre>
<pre><font color="#008000"> // TODO: add reinitialization code here</font></pre>
<pre><font color="#008000"> // (SDI documents will reuse this document)</font></pre>
<pre><font color="#008000"> m_message = "Default Message";</font></pre>
<pre><font color="#008000"> return TRUE;</font></pre>
<pre><font color="#008000">}</font></pre>
<P>With the document class's <font color="#008000">m_message</font> data member initialized, the application can display the data in the view window, which it does in the view class's <font color="#008000">OnDraw()</font> function, as shown in Listing
8.2.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 8.2—</I>FILEVIEW.CPP<I>—Displaying the Document's Data</I></P>
<pre><font color="#008000">void CFileView::OnDraw(CDC* pDC)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CFileDoc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> // TODO: add draw code for native data here</font></pre>
<pre><font color="#008000"> pDC->TextOut(20, 20, pDoc->m_message);</font></pre>
<pre><font color="#008000">}</font></pre>
<P>As long as the user is happy with the contents of the document, the program doesn't need to do anything else. But, of course, an application that doesn't allow the user to edit the application's documents is mostly useless. The File Demo application
displays a dialog box the user can use to edit the contents of the document, as shown in Listing 8.3.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 8.3—</I>FILEVIEW.CPP<I>—Changing the Document's Data</I></P>
<pre><font color="#008000">void CFileView::OnEditChangemessage()</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> // TODO: Add your command handler code here</font></pre>
<pre><font color="#008000"> </font></pre>
<pre><font color="#008000"> CChangeDlg dialog(this);</font></pre>
<pre><font color="#008000"> CFileDoc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> dialog.m_message = pDoc->m_message;</font></pre>
<pre><font color="#008000"> int result = dialog.DoModal();</font></pre>
<pre><font color="#008000"> if (result == IDOK)</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> pDoc->m_message = dialog.m_message;</font></pre>
<pre><font color="#008000"> pDoc->SetModifiedFlag();</font></pre>
<pre><font color="#008000"> Invalidate();</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000">}</font></pre>
<P>This function, which responds to the application's <U>E</U>dit, <U>C</U>hange Message command, displays the dialog box and, if the user exits the dialog box by clicking the OK button, transfers the string from the dialog box to the document's data
member. The call to the document class's <font color="#008000">SetModifiedFlag()</font> function notifies the class that its contents have been changed. After the user has changed the document's contents, they must save the data before exiting the
application (unless, that is, the user doesn't want to save the changes). The document class's <font color="#008000">Serialize()</font> function, handles the saving and loading of the document's data. Listing 8.4 shows the empty shell of <font
color="#008000">Serialize()</font> generated by AppWizard.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 8.4—</I>FILEVIEW.CPP<I>—The Document Class's </I>Serialize()<I> </I><I>Function</I></P>
<pre><font color="#008000">void CFileDoc::Serialize(CArchive& ar)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> if (ar.IsStoring())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> // TODO: add storing code here</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000"> else</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> // TODO: add loading code here</font></pre>
<pre><font color="#008000">}</font></pre>
<pre><font color="#008000">}</font></pre>
<P>Because the <font color="#008000">CString</font> class (of which <font color="#008000">m_message</font> is an object) defines the <font color="#008000">>></font> and <font color="#008000"><<</font> operators for transferring strings to and
from an archive, it's a simple task to save and load the document class's data. Simply add this line where the comment reminds you to add storing code:</P>
<pre><font color="#008000"> ar << m_message;</font></pre>
<P>Add this similar line where the loading code belongs:</P>
<pre><font color="#008000"> ar >> m_message;</font></pre>
<P>The <font color="#008000"><<</font> operator sends the <font color="#008000">CString</font> <font color="#008000">m_message</font> to the archive; the <font color="#008000">>></font> operator fills <font color="#008000">m_message</font>
from the archive. As long as all the document's member variables are simple data types like integers or characters, or MFC classes like <font color="#008000">CString</font> with these operators already defined, it is easy to save and load the data. The
operators are defined for these simple data types:</P>
<ul>
<li> <font color="#008000">BYTE</font></pre>
<li> <font color="#008000">WORD</font></pre>
<li> <font color="#008000">int</font> </P>
<li> <font color="#008000">LONG</font></pre>
<li> <font color="#008000">DWORD</font></pre>
<li> <font color="#008000">float</font></pre>
<li> <font color="#008000">double</font></pre>
</ul>
<H3><A ID="I6" NAME="I6"><B>Creating a Persistent Class</B></A></H3>
<P>But what if you've created your own custom class for holding the elements of a document? How can you make an object of this class persistent? You find the answers to these questions in this section.</P>
<P>Suppose that you now want to enhance the File Demo application so that it contains its data in a custom class called <font color="#008000">CMessages</font>. The member variable is now called <font color="#008000">m_messages</font> and is an instance of
<font color="#008000">CMessages</font>. This class holds three <font color="#008000">CString</font> objects, each of which must be saved and loaded if the application is going to work correctly. One way to arrange this is to save and load each individual
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -