?? ch07.htm
字號(hào):
</PRE>
<PRE>}
</PRE>
<P>There's nothing tricky about the SetMessage() and GetMessage() functions, which
perform their assigned tasks precisely. The Serialize() function, however, may inspire
a couple of questions. First, note that the first line of the body of the function
calls the base class's Serialize() function. This is a standard practice for many
functions that override functions of a base class. In this case, the call to CObject::Serialize()
doesn't do much because the CObject class's Serialize() function is empty. Still,
calling the base class's Serialize() function is a good habit to get into because
you may not always be working with classes derived directly from CObject.</P>
<P>After calling the base class's version of the function, Serialize() saves and
loads its data in much the same way a document object does. Because the data members
that must be serialized are CString objects, the program can use the >> and
<< operators to write the strings to the disk.</P>
<P>Towards the top of messages.cpp, after the include statements, add this line:</P>
<P>
<PRE>IMPLEMENT_SERIAL(CMessages, CObject, 0)
</PRE>
<P>The IMPLEMENT_SERIAL() macro is partner to the DECLARE_SERIAL() macro, providing
implementation for the functions that give the class its persistent capabilities.
The macro's three arguments are the name of the class, the name of the immediate
base class, and a schema number, which is like a version number. In most cases, you
use 0 or 1 for the schema number.</P>
<P>
<H3><A NAME="Heading8"></A>Using the CMessages Class in the Program</H3>
<P>Now that CMessages is defined and implemented, member functions of the MultiString
document and view classes can work with it. First, expand CMultiStringDoc and double-click
OnNewDocument() to edit it. Add these lines in place of the TODO comments.</P>
<P>
<PRE> m_messages.SetMessage(1, "Default Message 1");
m_messages.SetMessage(2, "Default Message 2");
m_messages.SetMessage(3, "Default Message 3");
</PRE>
<P>Because the document class can't directly access the data object's protected data
members, it initializes each string by calling the CMessages class's SetMessage()
member function.</P>
<P>Expand CMultiStringView and double-click OnDraw() to edit it. Here's how it should
look when you're finished:</P>
<P>
<PRE>void CMultiStringView::OnDraw(CDC* pDC)
{
CMultiStringDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(20, 20, pDoc->m_messages.GetMessage(1));
pDC->TextOut(20, 40, pDoc->m_messages.GetMessage(2));
pDC->TextOut(20, 60, pDoc->m_messages.GetMessage(3));
}
</PRE>
<P>As you did for File Demo, add a "Change Messages" item to the Edit menu.
Connect it to a view function called OnEditChangemessages. This function will change
the data by calling the CMessages object's member functions, as in Listing 7.7. The
view class's OnDraw() function also calls the GetMessage() member function to access
the CMessages class's strings.</P>
<P>
<H4>Listing 7.7  Editing the Data Strings</H4>
<PRE>void CMultiStringView::OnEditChangemessages()
{
CMultiStringDoc* pDoc = GetDocument();
CTime now = CTime::GetCurrentTime();
CString changetime = now.Format("Changed at %B %d %H:%M:%S");
pDoc->m_messages.SetMessage(1, CString("String 1 ") + changetime);
pDoc->m_messages.SetMessage(2, CString("String 2 ") + changetime);
pDoc->m_messages.SetMessage(3, CString("String 3 ") + changetime);
pDoc->SetModifiedFlag();
Invalidate();
</PRE>
<PRE>}
</PRE>
<P>All that remains is to write the document class's Serialize() function, where
the m_messages data object is serialized out to disk. You just delegate the work
to the data object's own Serialize() function, as in Listing 7.8.</P>
<P>
<H4>Listing 7.8   Serializing the Data Object</H4>
<PRE>void CMultiStringDoc::Serialize(CArchive& ar)
{
m_messages.Serialize(ar);
if (ar.IsStoring())
{
}
else
{
}
</PRE>
<PRE>}
</PRE>
<P>As you can see, after serializing the m_messages data object, not much is left
to do in the document class's Serialize() function. Notice that the call to m_messages.Serialize()
passes the archive object as its single parameter. Build MultiString now and test
it as you tested File Demo. It should do everything you expect.</P>
<P>
<H2><A NAME="Heading9"></A>Reading and Writing Files Directly</H2>
<P>Although using MFC's built-in serialization capabilities is a handy way to save
and load data, sometimes you need more control over the file-handling process. For
example, you might need to deal with your files nonsequentially, something the Serialize()
function and its associated CArchive object can't handle because they do stream I/O.
In this case, you can handle files almost exactly as they're handled by non-Windows
programmers: creating, reading, and writing files directly. Even when you need to
dig down to this level of file handling, MFC offers help. Specifically, you can use
the CFile class and its derived classes to handle files directly.</P>
<P>
<H3><A NAME="Heading10"></A>The CFile Class</H3>
<P>MFC's CFile class encapsulates all the functions you need to handle any type of
file. Whether you want to perform common sequential data saving and loading or construct
a random access file, the CFile class gets you there. Using the CFile class is a
lot like handling files the old-fashioned C-style way, except that the class hides
some of the busy-work details from you so that you can get the job done quickly and
easily. For example, you can create a file for reading with only a single line of
code. Table 7.1 shows the CFile class's member functions and their descriptions.</P>
<P>
<H4>Table 7.1  Member Functions of the CFile Class</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Function</B></TD>
<TD ALIGN="LEFT"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">CFile</TD>
<TD ALIGN="LEFT">Creates the CFile object. If passed a filename, it opens the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Destructor</TD>
<TD ALIGN="LEFT">Cleans up a CFile object that's going out of scope. If the file is open, it closes
that file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Abort()</TD>
<TD ALIGN="LEFT">Immediately closes the file with no regard for errors.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Close()</TD>
<TD ALIGN="LEFT">Closes the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Duplicate()</TD>
<TD ALIGN="LEFT">Creates a duplicate file object.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Flush()</TD>
<TD ALIGN="LEFT">Flushes data from the stream.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetFileName()</TD>
<TD ALIGN="LEFT">Gets the file's filename.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetFilePath()</TD>
<TD ALIGN="LEFT">Gets the file's full path.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetFileTitle()</TD>
<TD ALIGN="LEFT">Gets the file's title (the filename without the extension).</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetLength()</TD>
<TD ALIGN="LEFT">Gets the file's length.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetPosition()</TD>
<TD ALIGN="LEFT">Gets the current position within the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">GetStatus()</TD>
<TD ALIGN="LEFT">Gets the file's status.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">LockRange()</TD>
<TD ALIGN="LEFT">Locks a portion of the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Open()</TD>
<TD ALIGN="LEFT">Opens the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Read()</TD>
<TD ALIGN="LEFT">Reads data from the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Remove()</TD>
<TD ALIGN="LEFT">Deletes a file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Rename()</TD>
<TD ALIGN="LEFT">Renames the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Seek()</TD>
<TD ALIGN="LEFT">Sets the position within the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SeekToBegin()</TD>
<TD ALIGN="LEFT">Sets the position to the beginning of the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SeekToEnd()</TD>
<TD ALIGN="LEFT">Sets the position to the end of the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SetFilePath()</TD>
<TD ALIGN="LEFT">Sets the file's path.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SetLength()</TD>
<TD ALIGN="LEFT">Sets the file's length.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">SetStatus()</TD>
<TD ALIGN="LEFT">Sets the file's status.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">UnlockRange()</TD>
<TD ALIGN="LEFT">Unlocks a portion of the file.</TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">Write()</TD>
<TD ALIGN="LEFT">Writes data to the file.</TD>
</TR>
</TABLE>
</P>
<P>As you can see from Table 7.1, the CFile class offers plenty of file-handling
power. This section demonstrates how to call a few of the CFile class's member functions.
However, most of the other functions are just as easy to use.</P>
<P>Here's a sample snippet of code that creates and opens a file, writes a string
to it, and then gathers some information about the file:</P>
<P>
<PRE> // Create the file.
CFile file("TESTFILE.TXT", CFile::modeCreate | CFile::modeWrite);
// Write data to the file.
CString message("Hello file!");
int length = message.GetLength();
file.Write((LPCTSTR)message, length);
// Obtain information about the file.
CString filePath = file.GetFilePath();
Int fileLength = file.GetLength();
</PRE>
<P>Notice that you don't have to explicitly open the file when you pass a filename
to the constructor, whose arguments are the name of the file and the file access
mode flags. You can use several flags at a time simply by ORing their values together,
as in the little snippet above. These flags, which describe how to open the file
and which specify the types of valid operations, are defined as part of the CFile
class and are described in Table 7.2.</P>
<P>
<H4>Table 7.2  The File Mode Flags</H4>
<P>
<TABLE BORDER="1">
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT"><B>Flag</B></TD>
<TD ALIGN="LEFT"><B>Description</B></TD>
</TR>
<TR ALIGN="LEFT" VALIGN="TOP">
<TD ALIGN="LEFT">CFile::modeCreate</TD>
<TD ALIGN="LEFT">Creates a new file or truncates an existing file to length 0</TD>
</TR>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -