TN002: Formát dat objektu trvalé
Tato poznámka popisuje MFC rutin, které podporují trvalé objektů C++ a formát dat objektu při uložení do souboru.Platí pouze pro třídy se DECLARE_SERIAL a IMPLEMENT_SERIAL makra.
Problém
Implementace MFC pro trvalá data ukládá data pro mnoho objektů v jedné spojité části souboru.Objektu Serialize metoda převádí data objektu na kompaktní formát binární.
Provedení zaručuje, že všechna data uložena ve stejném formátu pomocí Třída CArchive.Použije CArchive objektu jako převaděče.Tento objekt potrvá od doby vytvoření dokud volání CArchive::Close.Tuto metodu lze volat pomocí programátor explicitně nebo implicitně se objekt při ukončení programu obor, který obsahuje CArchive.
Tato poznámka popisuje provádění CArchive členy CArchive::ReadObject a CArchive::WriteObject.Kód bude najít pro tyto funkce v Arcobj.cpp a provádění hlavních CArchive v Arccore.cpp.Kód uživatele nevyvolá ReadObject a WriteObject přímo.Místo toho používá tyto objekty určité třídy typu bezpečné vložení a extrakce operátory, které jsou generovány automaticky podle DECLARE_SERIAL a IMPLEMENT_SERIAL makra.Následující kód zobrazuje, jak WriteObject a ReadObject implicitně nazývá:
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))
Ukládání objektů do úložiště (CArchive::WriteObject)
Metoda CArchive::WriteObject zapíše data záhlaví, která slouží k rekonstrukci objektu.Tato data se skládá ze dvou částí: typ objektu a stavu objektu.Tato metoda je také odpovědné za udržování identity objektu vypsanou, takže jednou kopií uložen, bez ohledu na počet ukazatelů k objektu (včetně cyklické odkazy).
Ukládání (vložení) a obnovení objektů (extrakce) závisí na několika "manifestu konstanty." Jsou hodnoty, které jsou uloženy v binárním formátu a důležité informace do archivu (Poznámka předponu "w" označuje množství 16-bit):
Značka |
Description |
---|---|
wNullTag |
Používané ukazatele objekt NULL (0). |
wNewClassTag |
Označuje, že je popis třídy, která následuje nový kontext tohoto archivu (-1). |
wOldClassTag |
Označuje, že při čtení objektu třídy má byly vidět v tomto kontextu (0x8000). |
Při ukládání objektů archivu udržuje CMapPtrToPtr ( m_pStoreMap) je mapování z objektu uložených na 32bitové trvalé identifikátorem (PID).PID je přiřazena každý objekt jedinečný a každý jedinečný název třídy uloženého v rámci archivu.Tyto PID jsou vydaných postupně počínaje 1.Tyto PID mimo oblast působnosti archivu nemají žádný význam a jsou zejména Nezaměňovat s záznamu čísla nebo jiné položky identity.
V CArchive třídy, PID jsou 32bitové, ale jsou napsány jako 16-bit, pokud nejsou větší než 0x7FFE.Velké PID jsou zapsány jako 0x7FFF, následované PID 32-bit.Tato volba zachová kompatibilitu s projekty, které byly vytvořeny v předchozích verzích.
Při požadavku uložte objekt do archivu (obvykle pomocí operátoru globální kurzoru) s hodnotou NULL je provedena kontrola CObject ukazatel.Pokud má ukazatel hodnotu NULL, wNullTag je vložena do proudu archivu.
Pokud ukazatel není NULL a lze serializovat (třída je DECLARE_SERIAL třídy), kód kontroly m_pStoreMap a zjistěte, zda byl objekt již uložen.Pokud ano, vloží kód PID 32 bit přidružené k objektu do archivu datového proudu.
Pokud objekt nebyly uloženy před, existují dvě možnosti vzít v úvahu: objekt a přesný typ objektu (třída) jsou nový kontext tohoto archivu, nebo objekt je již vidět přesné typu.Určit, zda typ byl bylo vidět, kód dotazy m_pStoreMap pro CRuntimeClass objekt, který odpovídá CRuntimeClass objekt přidružený objekt uložit.Pokud shoda, WriteObject vloží značku, která je bitového OR z wOldClassTag a tento index.Pokud CRuntimeClass je nový kontext tohoto archivu WriteObject třídy přiřadí nového PID a vloží do archivu, předchází wNewClassTag hodnotu.
Popisovač pro tuto třídu se pak vloží do archivu pomocí CRuntimeClass::Store metoda.CRuntimeClass::StoreVloží číslo schématu třídy (viz níže) a text ASCII název třídy.Všimněte si, že použití názvu text ASCII nezaručuje jedinečnosti archivu ve všech aplikacích.Proto by značka datové soubory zabránit poškození.Po vložení informací třídy archivu umístí objekt m_pStoreMap a pak zavolá Serialize metoda třídy specifická data vložit.Objekt uvádění m_pStoreMap před voláním Serialize zabraňuje uložení v úložišti více kopií objektu.
Při návratu do počátečního volajícího (obvykle root sítě objekty), musíte zavolat CArchive::Close.Chcete-li provést další CFileoperace, musíte zavolat CArchive metody Flush zabránit poškození archivu.
[!POZNÁMKA]
Tato implementace ukládá pevný limit 0x3FFFFFFE indexů za místní archivace.Toto číslo představuje maximální počet jedinečných objekty a třídy, které lze uložit v jednom archivu, ale jeden disk soubor může mít neomezený počet kontextů archivu.
Načítání objektů z úložiště (CArchive::ReadObject)
Načítání (extrahování) používá objekty CArchive::ReadObject metoda a je převést z WriteObject.Stejně jako WriteObject, ReadObject nebyla volána přímo pomocí uživatelského kódu; kód uživatele by měla zavolat typu bezpečné extrakce operátor, který volá ReadObject s očekávané CRuntimeClass.To zajistí integritu typ operace výpisu.
Od WriteObject provedení přiřazeny rostoucí PID, počínaje 1 (0 předdefinované jako objekt NULL), ReadObject provedení můžete použít matici k udržení stavu místní archivace.Při PID je čtení z úložiště, pokud je větší než aktuální horní mez PID m_pLoadArray, ReadObject ví, že takto nového objektu (nebo popis třídy).
Schéma čísel
Číslo schématu, které je přiřazena třída při IMPLEMENT_SERIAL metoda třídy je nalezen, je "verze" implementace třídy.Schéma označuje implementace třídy, aby počet daný objekt byl proveden trvalé (obvykle označuje jako verze objektu).
Pokud chcete zachovat stejné třídy několika různými implementacemi časem, stovce schématu jako revidovat daného objektu Serialize implementace metody umožňují napsat kód, který lze načíst objekty uložené pomocí starší verze provedení.
CArchive::ReadObject Metoda CArchiveException při výskytu číslo schématu v trvalé úložiště, která se liší od počtu schématu popis třídy v paměti.Není snadné obnovit tuto výjimku.
Můžete použít VERSIONABLE_SCHEMA v kombinaci s (bitový OR) verze schématu zachovat výjimku je vyvolána.Pomocí VERSIONABLE_SCHEMA, kód může přijmout vhodná opatření jeho Serialize kontrolou vrácená hodnota funkce CArchive::GetObjectSchema.
Serializovat volání přímo
V mnoha případech režie schéma archivu obecný objekt WriteObject a ReadObject , není nutné.To je případ běžné serializaci dat do CDocument.V tomto případě Serialize metodu CDocument se nazývá přímo, nikoli s operátory výpisu nebo vložit.Obsah dokumentu může použít další obecné schéma archivu objektu.
Volání Serialize přímo má následující výhody a nevýhody:
Žádné další bajty přidávání do archivu před nebo po serializována objektu.Toto není pouze díky menší uložených dat, ale umožňuje implementovat Serialize rutin, které lze zpracovat všechny formáty souborů.
Jednotka MFC je vyladěn tak, aby se WriteObject a ReadObject implementace a souvisejících kolekcí nebudou propojeny do aplikace jiných účelu nepotřebujete další obecné schéma archivu objektu.
Kód není nutné obnovit původní čísla schématu.Tím daný kód serializace dokumentu za kódování schématu čísla, čísla verze formátu souboru nebo jakékoli identifikační čísla použít na začátku datové soubory.
Libovolný objekt, který je serializován s přímým voláním Serialize nelze použít CArchive::GetObjectSchema nebo musí popisovač vrácená hodnota (UINT) -1 označující, že neznámé verze.
Protože Serialize se nazývá přímo v dokumentu, není obvykle možné pro sub-objects dokumentu a odkazy na jejich nadřazený dokument archivovat.Tyto objekty musí být dána ukazatele jejich dokument kontejneru explicitně nebo musí používat CArchive::MapObject funkce mapovat CDocument ukazatele PID před tyto zpětné odkazy jsou archivovány.
Jak je uvedeno výše, by mělo kódovat verze a třídy informací, sami při volání Serialize přímo, což umožňuje stále zachování zpětné kompatibility se staršími soubory později změnit formát.CArchive::SerializeClass Funkce může být volána explicitně před přímo serializaci objektu nebo před voláním základní třídy.