Udostępnij za pośrednictwem


TN002: Trwałe Format danych obiektu

Uwaga ta zawiera opis procedur MFC, które obsługują trwałych obiektów C++ i format danych obiektu, gdy jest on przechowywany w pliku.Dotyczy to tylko klasy z DECLARE_SERIAL i IMPLEMENT_SERIAL makr.

Problem

MFC wykonania trwałych danych przechowuje dane dla wielu obiektów w pojedynczy, ciągły części pliku.Obiekt Serialize metoda tłumaczy dane obiektu na format binarny kompaktowy.

Wykonania gwarantuje, że wszystkie dane zapisane w formacie za pomocą Klasa CArchive.Używa on CArchive obiektu jako translator.Ten obiekt będzie się powtarzał, od czasu jest tworzony, do czasu wywołania CArchive::Close.Tę metodę można wywołać jawnie przez programistę lub niejawnie przez destruktor, kiedy program zakres, który zawiera CArchive.

Uwaga ta opisuje wykonania CArchive członków CArchive::ReadObject i CArchive::WriteObject.Można znaleźć kod dla tych funkcji w Arcobj.cpp i implementacja dla CArchive w Arccore.cpp.Kod użytkownika nie wywołuje ReadObject i WriteObject bezpośrednio.Zamiast tego, obiekty te są używane przez specyficzne typ palety wstawiania i ekstrakcji operatorów, które są generowane automatycznie przez DECLARE_SERIAL i IMPLEMENT_SERIAL makr.Następujący kod pokazuje, jak WriteObject i ReadObject nazywane są niejawnie:

class CMyObject : public CObject
{
    DECLARE_SERIAL(CMyObject)
};

IMPLEMENT_SERIAL(CMyObj, CObject, 1)

// example usage (ar is a CArchive&)
CMyObject* pObj;
CArchive& ar;
ar << pObj;        // calls ar.WriteObject(pObj)
ar >> pObj;        // calls ar.ReadObject(RUNTIME_CLASS(CObj))

Zapisywanie obiektów do magazynu (CArchive::WriteObject)

Metoda CArchive::WriteObject zapisuje dane nagłówka, który jest używany do rekonstrukcji obiektu.Dane składa się z dwóch części: typ obiektu i stan obiektu.Metoda ta jest również odpowiedzialny za utrzymywanie tożsamości obiektu zapisywane, tak, aby zapisane tylko jednej kopii, niezależnie od liczby wskaźników do tego obiektu (w tym wskaźników cykliczne).

Zapisywanie (Wstawianie) oraz przywracanie obiektów (ekstrahujące) opiera się na kilka "manifestu stałych." Są to wartości, które są przechowywane w binarny i dostarczają ważnych informacji dla archiwum (Uwaga prefiksu "w" oznacza ilości 16-bitowe):

Tag

Opis

wNullTag

Używane dla wskaźników obiektu NULL (0).

wNewClassTag

Wskazuje, że opis klasy, który następuje jest nowa w tym kontekście archiwum (-1).

wOldClassTag

Wskazuje, że klasa obiektu odczytywany zaobserwowano w tym kontekście (0x8000).

Podczas przechowywania obiektów, utrzymuje archiwum CMapPtrToPtr ( m_pStoreMap) który jest mapowanie obiektów przechowywanych 32-bitowy identyfikator trwałe (PID).PID jest przypisany do każdego obiektu unikatowy i każdy unikalną nazwę klasy zapisaną w kontekście archiwum.Te numery PID są wręcza kolejno począwszy od 1.Te numery PID poza zakresem archiwum nie ma znaczenia, a w szczególności mają nie należy mylić z numery rekordów lub inne elementy tożsamości.

W CArchive klasy, numery PID są 32-bitowych, ale one zapisywane są w postaci 16-bitowych, chyba że są one większe niż 0x7FFE.Duże numery PID są zapisywane jako 0x7FFF następuje PID 32-bitowych.To utrzymuje zgodność z projektów, które zostały utworzone we wcześniejszych wersjach.

Gdy żądanie zapisać obiekt archiwum (zazwyczaj za pomocą operatora globalnego wstawiania), dokonuje null CObject wskaźnik.Jeżeli wskaźnik jest pusty, wNullTag jest wstawiany do strumienia archiwum.

Jeżeli wskaźnik nie jest NULL i może być serializowany (klasa jest DECLARE_SERIAL klasy), kontrole kod m_pStoreMap , aby zobaczyć, czy obiekt został już zapisany.Jeśli tak, to kod wstawia PID 32-bitowe, skojarzone z tego obiektu do strumienia archiwum.

Jeśli obiekt nie został zapisany przed, istnieją dwie możliwości ponownego rozważenia: nowy kontekst to archiwum są zarówno obiekt, jak i dokładny typ obiektu (to znaczy, że klasa) albo obiekt jest typu dokładne już widzieliśmy.Aby ustalić, czy typ został oceniony, kwerendy kodu m_pStoreMap dla CRuntimeClass obiekt, który odpowiada CRuntimeClass obiektu skojarzonego z obiektem zapisywany.Jeśli są zgodne, WriteObject wstawia znacznik, który jest równe OR z wOldClassTag i indeks.Jeśli CRuntimeClass jest nowa w tym kontekście archiwum WriteObject tej klasy przypisuje nowy identyfikator PID i wstawi go do archiwum, poprzedzony wNewClassTag wartości.

Deskryptor dla tej klasy zostanie wstawiony na użyciu archiwum CRuntimeClass::Store metody.CRuntimeClass::StoreWstawia numer schematu klasy (patrz poniżej) i nazwę klasy tekstu ASCII.Należy zauważyć, że używanie nazwy tekstowe ASCII nie gwarantuje unikatowości archiwum całej aplikacji.W związku z tym należy oznakować pliki danych, aby uniknąć uszkodzenia.W następstwie wstawiania informacji klasy archiwum powoduje umieszczenie obiektu do m_pStoreMap , a następnie wywołuje Serialize metodę, aby wstawić dane specyficzne dla klasy.Umieszczanie obiektu na m_pStoreMap przed wywoływaniem Serialize uniemożliwia zapisanie w magazynie wielu kopii obiektu.

Po powrocie do początkowego wywołującego (zazwyczaj głównych sieci obiektów), trzeba wywołać CArchive::Close.Jeśli planujesz wykonać inne CFileoperacji, trzeba wywołać CArchive metoda opróżnić do zapobieżenia korupcji archiwum.

[!UWAGA]

Ta implementacja nakłada twardym limitem indeksów 0x3FFFFFFE per kontekstu archiwum.Liczba ta określa maksymalną liczbę unikatowych obiekty i klasy, które można zapisać w jednym, ale plik pojedynczego dysku może mieć nieograniczoną liczbę kontekstów archiwum.

Ładowanie obiektów z magazynu (CArchive::ReadObject)

Ładowanie (wyodrębnianie) obiektów zastosowań CArchive::ReadObject metody i jest przeciwieństwem poprawności WriteObject.Tak jak w WriteObject, ReadObject nie jest wywoływany bezpośrednio przez kod użytkownika; Kod użytkownika powinna wywołać operatora ekstrakcji typ palety, który wywołuje ReadObject z oczekiwaną CRuntimeClass.To już integralności typu operacji ekstraktu.

Ponieważ WriteObject wykonania przypisanych rosnące PID, począwszy od 1 (0 wstępnie jako obiekt NULL), ReadObject wdrażania można użyć tablicy do zarządzania stanem kontekstu archiwum.PID jest odczytywana od magazynu, jeśli numer PID jest większy niż bieżący górną granicę m_pLoadArray, ReadObject wie, że następuje nowy obiekt (lub opis klasy).

Numery schematu

Numer schematu, który jest przypisany do klasy po IMPLEMENT_SERIAL metody klasy napotkania, jest "wersja" Implementacja klasy.Schemat odwołuje się do implementacji klasy, nie na tyle razy, ile podany obiekt dokonano trwałe (zwykle określonych jako wersja obiektu).

Jeśli planowane jest utrzymywać kilka różnych implementacji w tej samej klasy w czasie, zwiększając schematu poprawić swoje obiektu Serialize implementacja metody umożliwi to pisanie kodu, który można załadować obiekty przechowywane przy użyciu starszych wersji wykonania.

CArchive::ReadObject Metoda wygeneruje CArchiveException po napotkaniu numer schematu w Magazyn trwały, która różni się od schematu liczba opis klasy w pamięci.Nie jest łatwe do odzyskania z tego wyjątku.

Można użyć VERSIONABLE_SCHEMA połączone z (bitowe OR) wersji schematu, aby zachować ten wyjątek od pojazdu.Za pomocą VERSIONABLE_SCHEMA, kod może podjąć odpowiednie działania jego Serialize funkcji, sprawdzając wartość zwracana z CArchive::GetObjectSchema.

Calling serializować bezpośrednio

W wielu przypadkach napowietrznej obiektu ogólnego systemu archiwum WriteObject i ReadObject nie jest konieczne.Jest to przypadek Szeregowanie danych do CDocument.W przypadku Serialize metoda CDocument nazywa się bezpośrednio, nie z operatorami wyciąg lub Wstaw.Zawartość dokumentu z kolei może użyć bardziej ogólny schemat archiwum obiektu.

Wywołanie Serialize bezpośrednio ma następujące zalety i wady:

  • Nie dodatkowe bajty są dodawane do archiwum, przed lub po obiektu jest seryjny.To nie tylko czyni danych zapisanych na mniejsze, ale umożliwia wdrożenie Serialize procedur, które może obsługiwać dowolną formatów plików.

  • Urządzenie MFC jest dostrojony tak WriteObject i ReadObject implementacji i kolekcje powiązanych nie zostaną połączone w aplikacji, chyba że potrzebujesz bardziej ogólny schemat archiwum obiektu dla niektórych innych celów.

  • Kod nie odzyskuje od starych numerów schematu.To sprawia, że kod serializacji dokumentu jest odpowiedzialny za numery schemat kodowania, numery wersji formatu pliku lub niezależnie od identyfikujący numery można używać na początku plików danych.

  • Każdy obiekt, który jest seryjny z bezpośrednie wywołanie Serialize , nie wolno używać CArchive::GetObjectSchema lub musi uchwyt wartość zwracana (UINT) -1 wskazującą, że wersja była nieznany.

Ponieważ Serialize nazywa się bezpośrednio w dokumencie, nie jest zwykle możliwe podobiektów dokumentu, aby zarchiwizować odniesienia do ich dokumentu nadrzędnego.Obiekty te muszą mieć wskaźnik do ich dokumentu kontenera jawnie lub użyć CArchive::MapObject funkcji mapowania CDocument wskaźnik PID, zanim te wskaźniki back, są zarchiwizowane.

Jak zauważono wcześniej, należy zakodować wersji i informacje dotyczące klas samodzielnie podczas wywołania Serialize bezpośrednio, umożliwiając później zmienić format, zachowując zgodność z starsze pliki.CArchive::SerializeClass Funkcja może zostać wywołana jawnie przed bezpośrednio szeregowania obiektu lub przed wywołaniem metody klasy podstawowej.

Zobacz też

Inne zasoby

Uwagi techniczne przez liczbę

Uwagi techniczne według kategorii