Сериализация нестандартных обьектов

Лабораторная работа № 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);

}