Сериализация нестандартных обьектов
Лабораторная работа № 8
«Работа с файлами»
Указания к выполнению лабораторной работы
Сериализация
Это процесс записи или чтения некоторого обьекта с носителя информации. В большинстве программ на Visual C++ вся работа с данными происходит в документах, поэтому этот урок будет ориентирован на работу с обьектом документа.
Вам предстоит создать приложение writer которое будет записывать на диск введенную в клиентской части программы строку, а затем по требованию пользователя загружать ее из файла.
Сериализация стандартных обьектов
Создание программы writer
При помощи AppWizard создайте однодокументное (SDI) приложение с именем writer:
1. Добавьте код, который позволит приложению получать и отображать вводимые пользоавтелем символы. Эти данные будут храниться в обьекте StringData класса CString, который принадлежит документу:
//writerDoc.h : интерфейс класса CWriterDoc
.
.
.
class CWriterDoc : public CDocument
{
protected: //создание только при сериализации
CWriterDoc();
DECLARE_DYNCREATE(CWriterDoc)
//Атрибуты
public:
CString StringData;
2. Обьект StringData необходимо инициализировать пустой строкой в конструкторе документа:
CWriterDoc::CWriterDoc()
{
StringData = “”;
}
3. При помощи ClassWizard свяжите сообщение WM_CHAR с методом OnChar() и затем добавьте код для сохранения вводимых символов в обьекте StringData:
void CWriterDoc:: OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CWriterDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData += nChar;
Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}
4. Чтобы вводимые пользователем символы отображались в клиентской части программы, добавьте в метод OnDraw следующий фрагмент:
void CWriterView::OnDraw(CDC* pDC)
{
CWriterDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(0, 0, pDoc->StringData);
}
Теперь программа получает символы от пользователя, отображает их в окне и сохраняет в обьект StringData.
Следующий этап решения поставленной задачи заключается в том, чтобы пользователь мог сохранить данные программы и загрузить их с диска.
Сериализация обьекта StringData
Класс документа (файл writerDoc.h) содержит встроенный метод Serialize(), который необходимо изменить следующим образом:
void CWriterDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
//код сохранения
ar << StringData;
}
else
{
// код загрузки
ar >> StringData;
}
}
В этом методе происходит сериализация обьекта StringData. Для этого методу Serialize() передается ссылка на обьект ar класса CArchive, причем работа с обьектом ar практически не отличается от работы с потоками cout и cin. В этом методе мы вызываем метод IsStoring() обьекта ar, чтобы узнать, был метод вызван для записи или для чтения, затем выполняются операции для сохранения или загрузки данных с диска.
На этом сериализация обьекта StringData окончена. Если пользователь захочет выйти из программы, не сохранив данные, программа должна вывести сообщение, а вернее предложение сохранить изменения в документ. Для этого необходимо сообщить приложению о том, что данные были изменены, это достигается простым вызовом метода класса CDocument - SetModifiedFlag(), в котором устанавливается флаг изменения документа:
void CWriterView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CWriterDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData += nChar;
Invalidate();
pDoc->SetModifiedFlag();
CView::OnChar(nChar, nRepCnt, nFlags);
}
Вот и все! Программа готова к работе.
Сериализация нестандартных обьектов
Допустим мы создали класс CData который включает в себя: строку - обьект dataклассаCString,а также методы для работы с этой строкой. Нам неходимо реализовать сериализацию обьектов этого класса.
1. При помощи AppWizard Создайте новую однодокументную (SDI) программу с именем serializer.
2. Выполните в VisualC++ команду File -> New, в открывшемся диалоговом окне перейдите на вкладку Files, затем добавьте в проект новый файл, указав имя которого как CData.h.
3. Включите в созданый файл приведенный ниже програмный код:
class CData: public CObject
{
private:
CString data;
DECLARE_SERIAL(CData);
public:
CData(){data = CString("");}
void AddText(CString text){data += text;}
void DrawText(CDC* pDC){pDC->TextOut(0, 0, data);}
void ClearText(){data = "";}
void Serialize(CArchive& archive);
}
Для того обеспечения сериализации обьектов данного класса необходимо:
- описать данный класс как производный от класса MFC CObject;
- включить в определения данного класса макрос Visual C++ DECLARE_SERIAL, который обьявляет методы, используемые в процессе сериализации;
- переопределить метод Serialize() класса CObject;
4. Добавте в проект новый файл CData.cpp, который нам будет необходим для переопределения метода Serialize() класса Cobject.
5. Включите в созданый файл приведенный ниже програмный код:
#include “stdafx.h”
#include “serializerDoc.h”
void CData::Serialize(CArchive& archive)
{
//Вызов метода Serialize() базового класса CObject
CObject::Serialize(archive);
//Сериализация обьекта data принадлежащегоклассу CData
if (archive.IsStoring())
{
archive << data;
}
else
{
archive >> data;
}
}
//Добавляем макрос, который обеспечивает сериализацию нашего обьекта при помощи //дополнительных методов
IMPLEMENT_SERIAL(CData, CObject, 0)
6. Включите в заголовочный файл документа (serializerDoc.h) ссылку на новый файл (чтобы документ мог взаимодействовать с классом CData) и создать обьект класса CData с именем DataObject:
// serializerDoc.h интерфейс класса CSerializerDoc
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "CData.h"
.
.
.
class CSerializerDoc : public CDocument
{
.
.
.
//Атрибуты
public:
CData DataObject;
.
.
.
}
7. Для сериализации обьекта DataObject следует вызвать его метод Serialize() внутри метода Serialize() документа (класс CSerializerDoc):
void CSerializerDoc::CSerializerDoc(CArchive& ar)
{
DataObject.Serialize(ar);
}
8. Для сохранения вводимых пользователем символов необходимо связать сообщение WM_CHAR с методом OnChar() и затем добавьте код для сохранения вводимых символов в обьекте DataObjectкласса CData:
void СSerializerView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CSerializerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//Вызов метода класса CData, который сохраняет вводимые символы в обьекте data
pDoc-> DataObject.AddText(CString(nChar));
Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}
9. Для вывода содержымого обьекта DataObject воспользуемся методом класса CData – DrawText(), вызывая его в методе OnDraw() класса СSerializerView:
void CSerializerView::OnDraw(CDC* pDC)
{
CSerializerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc-> DataObject.DrawText(pDC);
}