Cериализация для начинающих - Часть 1

ОГЛАВЛЕНИЕ

Это руководство описывает легкий способ перевода простого объекта в последовательную форму.

Данная статья является первой частью руководства по сериализации, состоящего из трех частей.

  • Часть 1 является введением в основы сериализации.
  • Часть 2 объясняет, как обрабатывать чтение данных из неисправных хранилищ данных и поддерживать контроль версий.
  • Часть 3 описывает, как переводить в последовательную форму сложные объекты.

Сериализация - это процесс записи или чтения объекта на или из постоянного носителя информации, такого как дисковый файл. Сериализация объекта требует трех составляющих:

  • Объект CFile, представляющий файл данных.
  • Объект CArchive, обеспечивающий контекст сериализации.
  • Объект, подвергающийся сериализации.

Шаг 1 – Открытие файла данных

Чтобы сериализовать объект в файл "foo.dat", откройте файл с соответствующим режимом доступа. В данном примере файл открывается в режиме монопольного доступа для чтения/записи.

// Открываем файл "foo.dat"
  CFile* pFile = new CFile();
  ASSERT (pFile != NULL);
  if (!pFile->Open ("foo.dat", CFile::modeReadWrite | CFile::shareExclusive)) {
      // Обрабатываем ошибку
      return;
  }

Шаг 2 – Подключение архива

Затем к файлу подключается объект CArchive. Архив предоставляет эффективный канал связи с постоянным хранилищем. Вместо прямого чтения из файла или записи в файл вы сериализуете данные в архив или из архива. Архиву необходимо знать, собираетесь ли вы его использовать для чтения или для записи данных. В этом примере осуществляется запись данных.

// Создание архива ...
  bool bReading = false;  // ... для записи
  CArchive* pArchive = NULL;
  try

  {
    pFile->SeekToBegin();
    UINT uMode = (bReading ? CArchive::load : CArchive::store);
    pArchive = new CArchive (pFile, uMode);
    ASSERT (pArchive != NULL);
  }

  catch (CException* pException)
  {
    // Обработка ошибки
    return;
  }

Шаг 3 – Сериализация объекта

Сериализация объекта выполняется с помощью вызова его метода serialize(). serialize() – это всего лишь созданный программистом метод. Он не имеет никакого отношения к объекту MFC CObject::Serialize(). Также вам не нужно  порождать ваш объект с помощью CObject. Метод serialize() принимает указатель на CArchive и возвращает информацию о состоянии в виде целого числа.

  int CFoo::serialize

    (CArchive* pArchive)

  {
    int nStatus = SUCCESS;

    // Сериализация данного объекта ...
    ...
       return (nStatus);
  }

Фактическая процедура сериализации выполняется быстро. При этом не мешает разобраться с парой важных моментов:

  • Такой же метод CFoo::serialize() используется для чтения/записи объекта из/в постоянное хранилище.
  • CFoo::serialize() не знает ничего о файле, к которому получает доступ.

Предположим, что CFoo представляет собой запись о сотруднике, содержащую пару элементов данных.

   class CFoo

  {
    // Конструктор/деструктор
    public:
      CFoo::CFoo();
      virtual CFoo::~CFoo();
 
    // Методы
    public:
      int serialize (CArchive* pArchive);
 
    // Элементы данных
    public:
      CString  m_strName;  // имя сотрудника
      int      m_nId;      // идентификатор сотрудника

  };

Потоковые операторы CArchive << и >> используются для чтения/записи элементов данных из/в архив. CArchive знает, как сериализовать простые типы данных, такие как int, float, DWORD, и объектные, такие как CString. Архив также знает, в режиме чтения или записи он находится. Вы можете запросить его режим с помощью вызова CArchive::IsStoring(). Метод сериализации CFoo можно написать таким образом:

   int CFoo::serialize

    (CArchive* pArchive)

  {
    int nStatus = SUCCESS;
    // Сериализация объекта ...
    ASSERT (pArchive != NULL);
    try

    {
      if (pArchive->IsStoring()) {
         // Запись имени и идентификатора сотрудника
         (*pArchive) << m_strName;
         (*pArchive) << m_nId;

      }

      else {
         // Чтение имени и идентификатора сотрудника
         (*pArchive) >> m_strName;
         (*pArchive) >> m_nId;
      }

    }

    catch (CException* pException)
    {
      nStatus = ERROR;
    }

    return (nStatus);

  }

Шаг 4 – Освобождение памяти

После завершения сериализации вы должны освободить память, закрыв архив и файл данных.

  pArchive->Close();
  delete pArchive;
  pFile->Close();
  delete pFile();

Заключение

Здесь сериализация была описана кратко, в двух словах. В Части 2 описывается, как обрабатывать чтение данных из неисправных хранилищ данных и поддерживать различные версии нашего объекта. В Части 3 рассматривается сериализация сложных объектов.

Автор: Ravi Bhavnani