TN002: 영구 개체 데이터 형식
이 참고가 파일에 저장 하는 경우 영구 C++ 개체 및 개체 데이터 형식을 지 원하는 MFC 루틴을 설명 합니다.이 클래스에만 적용 되는 DECLARE_SERIAL 및 IMPLEMENT_SERIAL 매크로.
문제
영구 데이터에 대 한 MFC 구현 파일의 연속 된 단일 부품의 여러 개체에 대 한 데이터를 저장합니다.개체의 Serialize 메서드 개체의 데이터는 압축 이진 형식으로 변환 합니다.
모든 데이터가 저장 되었는지에서 같은 서식을 사용 하 여 구현을 보장의 CArchive 클래스.사용 하는 CArchive 개체로 번역기.이 개체를 호출 하기 전에 생성 된 시간부터 유지 CArchive::Close.프로그램 포함 하는 범위를 벗어나면이 메서드는 프로그래머에 의해 명시적으로 나 암시적으로 소멸자가 호출할 수 있는 CArchive.
이 노트의 구현에 설명의 CArchive 멤버 CArchive::ReadObject 및 CArchive::WriteObject.Arcobj.cpp, 및 기본 구현에 대 한 이러한 함수에 대 한 코드를 찾을 수 CArchive arccore.cpp에서.사용자 코드를 호출 하지 않습니다 ReadObject 및 WriteObject 직접.대신 이러한 개체 자동으로 생성 된 클래스별 형식이 안전한 삽입 및 추출 연산자가 사용 되는 DECLARE_SERIAL 및 IMPLEMENT_SERIAL 매크로.다음 코드는 WriteObject 및 ReadObject 암시적으로 호출 됩니다.
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))
저장소 (CArchive::WriteObject)에 개체를 저장합니다.
메서드 CArchive::WriteObject 개체를 재구축하는 데 사용 되는 헤더 데이터를 씁니다.이 데이터는 두 부분으로 구성 됩니다: 개체 유형과 개체의 상태입니다.이 메서드는 순환 포인터 등 해당 개체에 대 한 포인터의 수에 관계 없이 단일 복사본만 저장 되도록 기록 되 고 있는 개체의 id를 유지 하는 데 담당 합니다.
(삽입)을 저장 및 복원 (압축 풀기) 개체에 의존 여러 "매니페스트 상수에서." 이러한 이진 파일에 저장 되 고 보관 ("w" 접두사 16 비트 수량을 나타내는 참고)에 중요 한 정보를 제공 하는 값입니다.
Tag |
설명 |
---|---|
wNullTag |
(0) NULL 개체 포인터를 사용 합니다. |
wNewClassTag |
뒤에 오는 클래스 설명 (-1)이 보관 컨텍스트를 새 인지를 나타냅니다. |
wOldClassTag |
읽는 중인 개체의 클래스를이 컨텍스트에서 (0x8000) 있었는지 여부를 나타냅니다. |
개체를 저장 하는 경우 보관 유지는 CMapPtrToPtr (에 m_pStoreMap) 32 비트 영구 식별자 (PID) 매핑을 저장 된 개체에서입니다.PID 마다 고유한 개체 및 보관의 컨텍스트 내에서 저장 된 모든 고유 클래스 이름으로 할당 됩니다.이러한 Pid 시작 1부터 순차적으로 전달 됩니다.이러한 Pid 의미가 보관 범위 밖에 있고, 특히 다른 identity 항목 레코드 번호와 혼동 하지 말아야 합니다.
에 CArchive 클래스, Pid 32 비트 이지만 0x7FFE 보다 큰 경우가 아니면 이러한 16 비트 쓰여집니다.큰 Pid로 0x7FFF PID로 32 비트 뒤에 기록 됩니다.이전 버전에서 만든 프로젝트와의 호환성을 유지 합니다.
(일반적으로 전역 삽입 연산자를 사용 하 여) 보관 하는 개체를 저장 하는 요청 될 때 NULL을 확인 이루어집니다 CObject 포인터입니다.포인터가 NULL 인 경우는 wNullTag 아카이브 스트림으로 삽입 됩니다.
포인터가 NULL이 아닌 고 serialize 될 수 있는 경우 (클래스는 DECLARE_SERIAL 클래스), 코드 검사는 m_pStoreMap 개체를 이미 저장 했는지 여부를 확인 합니다.삭제 되었으면 32 비트 PID 보관 스트림으로 해당 개체와 관련 코드를 삽입 합니다.
전에 개체를 저장 하지 않은 경우 고려해 야 할 두 가지 가능성이 있습니다: 개체와 개체의 정확한 형식 (클래스)이 보관 컨텍스트를 새로 추가 하거나 이미 알고 정확한 형식의 개체입니다.형식을 나타났습니다 여부를 결정 합니다 코드 쿼리는 m_pStoreMap 에 개의 CRuntimeClass 일치 하는 개체는 CRuntimeClass 개체가 저장 되는 개체와 연관 된.이면 일치 하는 항목, WriteObject 비트입니다 태그를 삽입 합니다. OR 의 wOldClassTag 및이 인덱스.경우는 CRuntimeClass 아카이브 컨텍스트에이 새로운 WriteObject 해당 클래스에 새 PID를 할당 하 고 아카이브를 앞에 삽입는 wNewClassTag 값입니다.
이 클래스에 대 한 설명자 다음을 사용 하 여 보관 파일에 삽입 되는 CRuntimeClass::Store 메서드.CRuntimeClass::Store스키마 클래스 (아래 참조)와 클래스 이름을 ASCII 텍스트를 삽입합니다.ASCII 텍스트 이름 사용 하도록 응용 프로그램 간에 아카이브 고유성 보장 하지 참고 합니다.따라서 데이터 손상을 방지 하기 위해 파일에 태그 합니다.클래스 정보를 삽입 하는 다음 개체에 아카이브를 배치는 m_pStoreMap 호출을 Serialize 클래스 관련 데이터를 삽입 하는 메서드.개체에 배치 하는 m_pStoreMap 호출 하기 전에 Serialize 개체의 여러 복사본을 저장소에 저장할 수 없으며.
(일반적으로 네트워크 개체의 루트) 초기 호출자로 반환 되 면 호출 해야 CArchive::Close.다른 작업을 수행 하려는 경우 CFile해야 호출할 작업을의 CArchive 메서드 플러시 아카이브 손상을 방지 하기 위해.
[!참고]
이 구현에 보관 컨텍스트마다 0x3FFFFFFE 인덱스에서 하드 제한을 설정 합니다.고유한 개체 및 클래스는 단일 보관 파일에 저장할 수 있는 최대 수가이 숫자를 나타냅니다 하지만 단일 디스크 파일 무제한 보관 컨텍스트가 있을 수 있습니다.
(CArchive::ReadObject) 저장소에서 개체를 로드합니다.
로드 (추출) 개체를 사용 하 여 CArchive::ReadObject 메서드에 반비례입니다 WriteObject.마찬가지로 WriteObject, ReadObject 사용자 코드에서 직접 호출 되지 않습니다 사용자 코드를 호출 하는 형식 안전 추출 연산자 호출 해야 ReadObject 로 예상 되는 CRuntimeClass.이 무결성 추출 작업의 종류에 대 한.
이후에 WriteObject 구현 증가 Pid를 1부터 할당 (0입니다 미리으로 NULL 개체)는 ReadObject 구현을 사용할 수 있는 배열 보관 컨텍스트의 상태를 유지 하기 위해.PID는 읽을 때 저장소에서 PID는 현재 상한 보다 크면는 m_pLoadArray, ReadObject 새 개체 (또는 클래스 설명) 오는 것을 알고 있습니다.
스키마 번호
클래스에 할당 되는 스키마 번호를 때의 IMPLEMENT_SERIAL 메서드는 클래스의 발생, "버전" 클래스 구현입니다.클래스의 구현에는 스키마를 참조 하 고 않은 횟수를 지정 된 개체 (대개 개체 버전으로 라고도 함) 영구 했습니다.
같은 클래스의 몇 가지 다른 구현을 유지 관리 하려는 경우 해당 개체를 수정할 때 스키마 증가 Serialize 메서드 구현을 구현 이전 버전을 사용 하 여 저장 된 개체를 로드할 수 있습니다 코드를 작성 하 여 사용 합니다.
CArchive::ReadObject 는 메서드에서 throw는 CArchiveException 때 발견 스키마 번호는 영구 저장소 클래스 설명에 메모리 스키마 개수와 다릅니다.이 예외를 복구 하는 것은 어렵지 않습니다.
사용할 수 있습니다 VERSIONABLE_SCHEMA 와 함께 (비트 OR)이이 예외를 throw 하 고 유지 하는 스키마 버전입니다.사용 하 여 VERSIONABLE_SCHEMA, 코드 적절 한 조치를 취할 수 해당 Serialize 함수에서 반환 값을 검사 하 여 CArchive::GetObjectSchema.
직접 호출을 Serialize
대부분의 오버 헤드는 일반 개체 보관 체계의 경우 WriteObject 및 ReadObject 필요 하지 않습니다.일반적인 데이터를 직렬화 하는 작업의 경우가는 CDocument.이 경우는 Serialize 메서드는 CDocument 추출 이나 삽입 연산자를 않습니다 직접 호출 됩니다.문서의 내용을 차례로 더 일반적인 개체 보관 구성표를 사용할 수 있습니다.
호출 Serialize 직접 다음과 같은 장점과 단점이 있습니다.
없음 추가 바이트에 보관 하기 전에 개체를 serialize 된 후 추가 됩니다.이렇게 저장 된 데이터는 작게 뿐 아니라 구현할 수 있습니다 Serialize 루틴 모두 처리할 수 있는 파일 형식입니다.
MFC를 조정 하도록 WriteObject 및 ReadObject 구현과 관련된 컬렉션 됩니다 없습니다 수 연결 응용 프로그램에 보다 일반적인 개체 보관 구성표를 다른 용도로 필요 하지 않은.
코드는 이전 스키마 번호에서 복구할 필요가 없습니다.이 문서 serialization 코드 인코딩 스키마 번호 나 파일 형식의 버전 번호를 식별 하는 번호에 대 한 책임이 있습니다 시작할 때의 데이터 파일을 사용 합니다.
개체에 대 한 직접 호출을 serialize Serialize 사용 해야 CArchive::GetObjectSchema 또는 해야 반환 값이-1 (UINT) 핸들을 나타내는 버전 알려진 없습니다.
때문에 Serialize 라고 직접 문서에는 일반적으로 문서는 상위 문서에 대 한 참조를 보관 하는 하위 개체에 대 한 불가능 합니다.이러한 개체에 대 한 포인터를 컨테이너 문서에 명시적으로 부여 해야 합니다 또는 사용 해야 CArchive::MapObject 매핑할 함수는 CDocument 이러한 백 포인터 보관 하기 전에 PID에 대 한 포인터입니다.
앞에서 설명 했 듯이 버전 인코딩 및 호출 하면 사용자가 직접 클래스 정보 해야 Serialize 직접 형식에 오래 된 파일을 이전 버전과 호환성을 유지 하면서도 나중에 변경할 수 있도록 합니다.CArchive::SerializeClass 함수 호출 명시적으로 직접 개체를 serialize 하기 전에 또는 기본 클래스를 호출 하기 전에.