TN002: Formát dat trvalých objektů
Tato poznámka popisuje MFC rutin, které podporují trvalé objektů jazyka C++ a formát dat objektu při uložení do souboru.To platí pouze pro třídy, které se DECLARE_SERIAL a IMPLEMENT_SERIAL makra.
Problém
Implementace MFC pro trvalá data ukládá data pro mnoho objektů v jedné souvislé části souboru.Objektu Serialize metoda převede na kompaktní binární formát dat objektu.
Provedení zaručuje, že všechna data ve stejném formátu uložena pomocí Třída CArchive.Používá CArchive objekt jako překladateli.Tento objekt přetrvává od doby vytvoření dokud nezavoláte CArchive::Close.Tuto metodu lze volat pomocí programátor explicitně nebo implicitně destruktoru při ukončení program obor, který obsahuje CArchive.
Tato poznámka popisuje provádění CArchive členy CArchive::ReadObject a CArchive::WriteObject.Zjistíte kód pro tyto funkce v Arcobj.cpp a hlavní implementace pro CArchive v Arccore.cpp.Uživatelský kód nevolá ReadObject a WriteObject přímo.Místo toho používají tyto objekty specifické pro třídu typově bezpečné vložení a extrakce operátory, které jsou generovány automaticky a DECLARE_SERIAL a IMPLEMENT_SERIAL makra.Následující kód ukazuje, jak WriteObject a ReadObject jsou implicitně volána:
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 hlavičky, 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 je uložen pouze jedné kopie bez ohledu na počet ukazatelů daného objektu (včetně kruhových ukazatelů).
Ukládání (vkládání) a obnovení objektů (extrakce) závisí na několika "manifestu konstanty." Jsou to hodnoty, které jsou uloženy v binárním a poskytují důležité informace do archivu (Všimněte si, že předpona "w" označuje množství 16 bitů):
Značka |
Popis |
---|---|
wNullTag |
Používá se pro ukazatele objektu NULL (0). |
wNewClassTag |
Označuje, že třída popis, který následuje je nový kontext tohoto archivu (-1). |
wOldClassTag |
Označuje, že třída objektu přečtení zaznamenala v této souvislosti (0x8000). |
Při ukládání objektů, udržuje archiv CMapPtrToPtr ( m_pStoreMap) což je mapování z objektu uložených 32-bit trvalá identifikační (číslo PID).PID je přiřazen pro každý objekt jedinečný a každý jedinečný název třídy uložené 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 zejména jsou Nezaměňovat s záznam čísel nebo jiných položek identity.
V CArchive třídy, PID jsou 32-bit, ale jsou nejsou větší než 0x7FFE zapsána jako 16-bit.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 na objekt uložit do archivu (obvykle pomocí operátoru globální kurzor) s hodnotou null je provedena kontrola třídy CObject ukazatele.Pokud má ukazatel hodnotu NULL, wNullTag je vložena do proudu archivu.
Pokud ukazatel myši není NULL a lze serializovat (třída je DECLARE_SERIAL třídy), kód kontroly m_pStoreMap Chcete-li zjistit, zda již byl uložen objektu.Pokud ano, vloží kód PID 32-bit, spojené s tímto objektem do archivu datového proudu.
Pokud před nebyl objekt uložen, jsou dvě možnosti, které je třeba zvážit: objekt a přesný typ objektu (třída) je nový kontext tohoto archivu nebo objekt je již vidět přesné typu.Chcete-li zjistit, zda typ vrátil, kód dotazy m_pStoreMap pro CRuntimeClass objekt, který odpovídá CRuntimeClass objekt přidružený objekt uložit.Pokud existuje shoda, WriteObject vloží značku, která je, že výsledkem bitového OR z wOldClassTag a tento index.Pokud CRuntimeClass je nový kontext tohoto archivu, WriteObject nového PID přiřadí dané třídy a vloží do archivu, předchází wNewClassTag hodnotu.
Popisovač pro tuto třídu je pak vložen do archivu pomocí CRuntimeClass::Store metody.CRuntimeClass::StoreVloží číslo schématu třídy (viz níže) a ASCII textový název třídy.Všimněte si, že použití názvu text ASCII není zárukou jedinečnosti archivu ve všech aplikacích.Proto by měla značka datové soubory, aby se zabránilo poškození.Po vložení údaje o třídě archivu umístí objekt m_pStoreMap a pak zavolá Serialize metody pro vložení dat specifické pro třídu.Uvedení objektu do m_pStoreMap pomoc Serialize zabrání více kopií objektu ukládány do úložiště.
Při návratu k původní volající (obvykle root síťových objektů), je třeba volat CArchive::Close.Pokud chcete provést další CFileoperace, musíte zavolat CArchive metoda vyprázdnění Chcete-li zabránit poškození archivu.
[!POZNÁMKA]
Tato implementace ukládá pevný limit 0x3FFFFFFE indexů za archivní kontext.Tato hodnota představuje maximální počet jedinečné objekty a třídy, které mohou být uloženy v jednom archivu, ale soubor jeden disk může mít neomezený počet kontextů archivu.
Načítání objektů z úložiště (CArchive::ReadObject)
Načítání (extrakce) používá objekty CArchive::ReadObject metoda a je konverzace z WriteObject.Stejně jako u WriteObject, ReadObject není volána přímo v uživatelském kódu; uživatelský kód by měl zavolat operátoru extrakce zajišťující bezpečnost typů, který volá ReadObject s očekávané CRuntimeClass.To zajistí integritu typ operace výpisu.
Protože WriteObject implementace přiřazené rostoucí PID, počínaje číslem 1 (0 předem definována jako objekt NULL), ReadObject provedení můžete použít pole k udržení stavu archivní kontext.Při PID čtení z úložiště, pokud je větší než aktuální horní mez PID m_pLoadArray, ReadObject ví, že následuje nový objekt (nebo popisu třídy).
Schéma čísel
Číslo schématu, který je přiřazen ke třídě při IMPLEMENT_SERIAL metoda třídy je zjištěna, je "verze" implementace třídy.Schéma se vztahuje k implementaci třídy, aby počet daného objektu byla provedena trvalé (obvykle označovány jako verze objektu).
Pokud chcete udržovat několik různých implementacích stejného druhu v čase, zvyšující schéma, jak opravit váš objekt Serialize implementace metody vám umožňuje napsat kód, který můžete načíst uložené pomocí starší verze provedení.
CArchive::ReadObject Metoda vyvolá CArchiveException při výskytu číslo schématu v trvalé úložiště, která se liší od schématu počet popis třídy v paměti.Není snadné obnovit tuto výjimku.
Můžete použít VERSIONABLE_SCHEMA v kombinaci s (bitové OR) verzi schématu zachovat vyvolání výjimky.Pomocí VERSIONABLE_SCHEMA, váš kód může přijmout vhodná opatření jeho Serialize funkce kontrolou návratová hodnota z CArchive::GetObjectSchema.
Serializovat volání přímo
V mnoha případech režie schématu obecný objekt archivu WriteObject a ReadObject je nezbytné.Toto je běžný případ serializace dat do CDocument.V tomto případě Serialize metoda CDocument se nazývá přímo, nikoli s operátory extrakt nebo vložit.Obsah dokumentu zase použít obecnější archivu schématu objektu.
Volání Serialize přímo má následující výhody a nevýhody:
Žádné další bajty jsou přidány do archivu před nebo po je serializovat objekt.Nejen díky tomu uložených dat menší, však umožňuje implementovat Serialize rutin, které lze zpracovat všechny formáty souborů.
Knihovny MFC je nastaven tak, že WriteObject a ReadObject implementace a souvisejících kolekcí nebudou propojeny do vaší aplikace, pokud potřebujete další obecné schéma archivu objekt jiného důvodu.
Obnovit původní čísla schématu nemá váš kód.Díky kódu serializace dokumentu za kódování schéma čísel, čísel verzí souborů formátu nebo jakékoliv identifikační čísla použít na začátku datové soubory.
Libovolný objekt, který je serializován pomocí přímého volání Serialize nesmí být použity CArchive::GetObjectSchema nebo musí úchyt vrácená hodnota -1 (UINT) označující, že byla verze neznámý.
Vzhledem k tomu, Serialize se nazývá přímo v dokumentu, není obvykle možné dílčí objekty dokumentu k archivaci odkazy na jejich nadřazený dokument.Tyto objekty musí ukazatel na jejich dokument kontejneru explicitně, nebo je třeba použít CArchive::MapObject funkce mapovat CDocument ukazatel na PID před tyto zpětné odkazy jsou archivovány.
Jak bylo uvedeno dříve, můžete kódovat verze a třídy informací, sami při volání Serialize přímo, což umožňuje změnit formát později, ale zároveň zachovat zpětnou kompatibilitu se staršími soubory.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.