Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Catatan ini menjelaskan rutinitas MFC yang mendukung objek C++ persisten dan format data objek saat disimpan dalam file. Ini hanya berlaku untuk kelas dengan makro DECLARE_SERIAL dan IMPLEMENT_SERIAL .
Masalah
Implementasi MFC untuk data persisten menyimpan data untuk banyak objek dalam satu bagian file yang bersebelahan. Metode objek Serialize
menerjemahkan data objek ke dalam format biner yang ringkas.
Implementasi menjamin bahwa semua data disimpan dalam format yang sama dengan menggunakan Kelas CArchive. Ini menggunakan CArchive
objek sebagai penerjemah. Objek ini bertahan sejak dibuat hingga Anda memanggil CArchive::Close. Metode ini dapat dipanggil baik secara eksplisit oleh programmer atau secara implisit oleh destruktor ketika program keluar dari cakupan yang berisi CArchive
.
Catatan ini menjelaskan implementasi CArchive
anggota CArchive::ReadObject dan CArchive::WriteObject. Anda akan menemukan kode untuk fungsi-fungsi ini di Arcobj.cpp, dan implementasi utama untuk CArchive
di Arccore.cpp. Kode pengguna tidak memanggil ReadObject
dan WriteObject
secara langsung. Sebagai gantinya, objek-objek ini digunakan oleh operator penyisipan dan ekstraksi yang aman untuk tipe khusus kelas, yang dihasilkan secara otomatis oleh makro DECLARE_SERIAL dan IMPLEMENT_SERIAL. Kode berikut menunjukkan bagaimana WriteObject
dan ReadObject
secara implisit disebut:
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))
Menyimpan Objek ke Penyimpanan (CArchive::WriteObject)
Metode CArchive::WriteObject
menulis data header yang digunakan untuk membangun ulang objek. Data ini terdiri dari dua bagian: jenis objek dan status objek. Metode ini juga bertanggung jawab untuk mempertahankan identitas objek yang ditulis, sehingga hanya satu salinan yang disimpan, terlepas dari jumlah pointer ke objek tersebut (termasuk penunjuk melingkar).
Menyimpan (menyisipkan) dan memulihkan (mengekstrak) objek bergantung pada beberapa "konstanta manifes." Ini adalah nilai yang disimpan dalam biner dan memberikan informasi penting ke arsip (perhatikan awalan "w" menunjukkan jumlah 16-bit):
Etiket | Deskripsi |
---|---|
wNullTag | Digunakan untuk penunjuk objek NULL (0). |
wNewClassTag | Menunjukkan deskripsi kelas baru yang mengikuti untuk konteks arsip ini (-1). |
wOldClassTag | Menunjukkan kelas objek yang dibaca telah terlihat dalam konteks ini (0x8000). |
Saat menyimpan objek, arsip mempertahankan CMapPtrToPtr ( m_pStoreMap) yang merupakan pemetaan dari objek tersimpan ke pengidentifikasi persisten (PID) 32-bit. PID ditetapkan ke setiap objek unik dan setiap nama kelas unik yang disimpan dalam konteks arsip. PID ini dibagikan secara berurutan mulai dari 1. PID ini tidak memiliki signifikansi di luar lingkup arsip dan, khususnya, tidak akan bingung dengan nomor rekaman atau item identitas lainnya.
CArchive
Di kelas , PID adalah 32-bit, tetapi ditulis sebagai 16-bit kecuali mereka lebih besar dari 0x7FFE. PID besar ditulis sebagai 0x7FFF diikuti oleh PID 32-bit. Ini mempertahankan kompatibilitas dengan proyek yang dibuat di versi sebelumnya.
Ketika permintaan dibuat untuk menyimpan objek ke arsip (biasanya dengan menggunakan operator penyisipan global), pemeriksaan dilakukan untuk pointer NULL CObject . Jika pointer adalah NULL, wNullTag dimasukkan ke dalam aliran arsip.
Jika penunjuk bukan NULL dan dapat diserialisasikan (kelas adalah DECLARE_SERIAL
kelas), kode memeriksa m_pStoreMap untuk melihat apakah objek telah disimpan. Jika sudah, kode menyisipkan PID 32-bit yang terkait dengan objek tersebut ke dalam aliran arsip.
Jika objek belum pernah disimpan sebelumnya, ada dua kemungkinan untuk dipertimbangkan: baik objek maupun jenis yang tepat (yaitu, kelas) objek tersebut baru untuk konteks arsip ini, atau objek memiliki jenis yang tepat yang sudah terlihat. Untuk menentukan apakah tipe telah terlihat, kode memeriksa m_pStoreMap untuk objek CRuntimeClass yang sesuai dengan objek yang terkait dengan objek yang disimpan. Jika ada kecocokan, WriteObject
menyisipkan tag yang merupakan hasil operasi bit-wise dari OR
dan indeks ini. CRuntimeClass
Jika CRuntimeClass
baru di dalam konteks arsip ini, maka menetapkan PID baru ke kelas tersebut dan menyisipkannya ke dalam arsip, yang didahului oleh nilai wNewClassTag.
Deskriptor untuk kelas ini kemudian dimasukkan ke dalam arsip menggunakan CRuntimeClass::Store
metode .
CRuntimeClass::Store
menyisipkan nomor skema kelas (lihat di bawah) dan nama teks ASCII kelas. Perhatikan bahwa penggunaan nama teks ASCII tidak menjamin keunikan arsip di seluruh aplikasi. Oleh karena itu, Anda harus menandai file data Anda untuk mencegah kerusakan. Setelah penyisipan informasi kelas, arsip menempatkan objek ke dalam m_pStoreMap lalu memanggil Serialize
metode untuk menyisipkan data khusus kelas. Menempatkan objek ke dalam m_pStoreMap sebelum memanggil Serialize
mencegah beberapa salinan objek disimpan ke penyimpanan.
Saat kembali ke pemanggil awal (biasanya akar jaringan objek), Anda harus memanggil CArchive::Close. Jika Anda berencana untuk melakukan operasi CFile lainnya, Anda harus memanggil CArchive
metode Flush untuk mencegah kerusakan arsip.
Nota
Implementasi ini memberlakukan batas keras indeks 0x3FFFFFFE per konteks arsip. Angka ini menunjukkan jumlah maksimum objek dan kelas unik yang dapat disimpan dalam satu arsip, tetapi satu file disk dapat memiliki sejumlah konteks arsip yang tidak terbatas.
Memuat Objek dari Penyimpanan (CArchive::ReadObject)
Memuat (mengekstrak) objek menggunakan CArchive::ReadObject
metode dan merupakan kebalikan dari WriteObject
. Seperti halnya WriteObject
, ReadObject
tidak dipanggil langsung oleh kode pengguna; kode pengguna harus memanggil operator ekstraksi jenis aman yang memanggil ReadObject
dengan CRuntimeClass
yang diharapkan. Ini memastikan integritas jenis operasi ekstrak.
WriteObject
Karena implementasi yang menetapkan PID bertambah, memulai dari 1 (0 telah ditentukan sebagai objek NULL), ReadObject
implementasi dapat menggunakan array untuk menjaga status konteks arsip. Ketika PID dibaca dari penyimpanan, jika PID lebih besar daripada batas atas m_pLoadArray yang ada saat ini, ReadObject
mengetahui bahwa objek baru (atau deskripsi kelas) akan mengikuti.
Nomor Skema
Nomor skema, yang ditetapkan ke kelas ketika metode IMPLEMENT_SERIAL
dari kelas tersebut ditemui, adalah "versi" dari implementasi kelas. Skema mengacu pada implementasi kelas, bukan berapa kali objek tertentu telah dibuat persisten (biasanya disebut sebagai versi objek).
Jika Anda ingin mempertahankan beberapa implementasi yang berbeda dari kelas yang sama dari waktu ke waktu, meningkatkan skema saat Anda merevisi implementasi metode objek Serialize
Anda akan memungkinkan Anda menulis kode yang dapat memuat objek yang disimpan dengan menggunakan versi implementasi yang lebih lama.
Metode ini CArchive::ReadObject
akan melempar CArchiveException ketika menemukan nomor skema di penyimpanan persisten yang berbeda dari jumlah skema deskripsi kelas dalam memori. Tidak mudah untuk pulih dari pengecualian ini.
Anda dapat menggunakan VERSIONABLE_SCHEMA
yang dikombinasikan dengan (bitwise OR) versi skema Anda untuk mencegah pengecualian ini dilemparkan. Dengan menggunakan VERSIONABLE_SCHEMA
, kode Anda dapat mengambil tindakan yang sesuai dalam fungsinya Serialize
dengan memeriksa nilai pengembalian dari CArchive::GetObjectSchema.
Memanggil Serialisasi Secara Langsung
Dalam banyak kasus, overhead dari skema arsip objek umum WriteObject
dan ReadObject
tidak diperlukan. Ini adalah kasus umum untuk menserialisasikan data ke dalam CDocument. Dalam hal ini, metode Serialize
dari CDocument
dipanggil secara langsung, bukan dengan operator ekstrak atau sisipkan. Konten dokumen pada gilirannya dapat menggunakan skema arsip objek yang lebih umum.
Memanggil Serialize
secara langsung memiliki kelebihan dan kekurangan berikut:
Tidak ada byte tambahan yang ditambahkan ke arsip sebelum atau sesudah objek diserialisasikan. Ini tidak hanya membuat data yang disimpan lebih kecil, tetapi memungkinkan Anda menerapkan
Serialize
rutinitas yang dapat menangani format file apa pun.MFC telah dikonfigurasikan agar implementasi
WriteObject
danReadObject
serta koleksi terkait tidak akan ditautkan ke dalam aplikasi Anda, kecuali Anda memerlukan skema arsip objek yang lebih umum untuk tujuan lain.Kode Anda tidak perlu memulihkan nomor skema lama. Ini membuat kode serialisasi dokumen Anda bertanggung jawab untuk mengodekan nomor skema, nomor versi format file, atau nomor identifikasi apa pun yang Anda gunakan di awal file data Anda.
Objek apa pun yang diserialisasi dengan panggilan langsung ke
Serialize
tidak boleh menggunakanCArchive::GetObjectSchema
atau harus menangani nilai pengembalian (UINT)-1 yang menunjukkan bahwa versi tidak diketahui.
Karena Serialize
dipanggil langsung pada dokumen Anda, biasanya tidak mungkin bagi sub-objek dokumen untuk mengarsipkan referensi ke dokumen induk mereka. Objek-objek ini harus diberikan penunjuk ke dokumen kontainer mereka secara eksplisit, atau Anda harus menggunakan fungsi CArchive::MapObject untuk memetakan penunjuk ke PID sebelum penunjuk balik ini diarsipkan.
Seperti disebutkan sebelumnya, Anda harus mengodekan informasi versi dan kelas sendiri ketika Anda memanggil Serialize
secara langsung, memungkinkan Anda untuk mengubah format nanti sambil tetap mempertahankan kompatibilitas mundur dengan file yang lebih lama. Fungsi CArchive::SerializeClass
ini dapat dipanggil secara eksplisit sebelum secara langsung membuat serial objek atau sebelum memanggil kelas dasar.
Lihat juga
Catatan Teknis berdasarkan Angka
Catatan Teknis menurut kategori