1. Ikhtisar
Saat menulis program database di Delphi, operasi impor dan ekspor data sering kali dilibatkan, seperti: menyimpan data dalam database besar sebagai file portabel agar mudah dibaca di luar; database sebagai file data, lebih mudah untuk bertukar data di dalam dan antar program, dan menghindari langkah-langkah rumit dalam bertukar data melalui memori, misalnya, dalam program laporan umum yang ditulis oleh penulis, kontrol ini digunakan sebagai pembawa informasi data pengiriman.
2. Ide dasar
Sebagai kontrol penyimpanan datagram, ia harus dapat menyimpan dan membaca informasi dasar kumpulan data (seperti: nama field, nama tampilan field, tipe data field, jumlah record, jumlah field, nilai saat ini dari field yang ditentukan dalam catatan yang ditentukan, dll.), dan harus Dapat memberikan karakteristik pengemasan yang lebih baik untuk kemudahan penggunaan.
Berdasarkan hal ini, penulis menggunakan karakteristik berorientasi objek Delphi5.0 untuk merancang dan mengembangkan kontrol penyimpanan datagram.
3. Metode pelaksanaan
Tuliskan unit kode berikut:
satuan File IbDb;
antarmuka
Menggunakan Windows, SysUtils, Kelas, Formulir, Db, DbTables, Dialog;
Konstan
Bendera = 'Datagram-Jixing Software Studio';
Jenis
TDsException = Kelas(Pengecualian);
TIbStorage = kelas(TComponent)
Pribadi
FRptJudul: string; //Deskripsi datagram penyimpanan
FPageHead: string; //Deskripsi tajuk halaman
FPageFoot: string; //Deskripsi kaki
FFieldNames: TStrings; //Tabel nama bidang
FStreamIndex: TStrings; //indeks bidang
FStream: TStream; //Streaming yang menyimpan konten lapangan
FFieldCount: Integer; //Jumlah bidang
FRecordCount: Integer; //Jumlah catatan
FOpenFlag: Boolean; // Apakah aliran dibuat benderanya
terlindung
procedure Reset; //Reset---hapus isi aliran
procedure SaveHead(ADataSet: TDataSet; Fp: TStream); //Informasi header laporan penyimpanan
prosedur LoadTableToStream(ADataSet: TDataSet); //Penyimpanan data catatan
procedure IndexFields(ADataSet: TDataSet); //Simpan nama field dari kumpulan data ke dalam daftar
procedure GetHead(Fp: TFileStream); //Simpan informasi header laporan
procedure GetIndex(Fp: TFileStream); //Membuat indeks aliran data
procedure GetFieldNames(Fp: TFileStream); //Baca tabel nama field dari stream
function GetFieldName(AIndex: Integer): string; //Dapatkan nama field
fungsi GetFieldDataType(AIndex: Integer): TFieldType;
function GetDisplayLabel(AIndex: Integer): string; //Dapatkan nama tampilan bidang
procedure SaveFieldToStream(AStream: TStream; AFfield: TField); //Simpan field ke dalam aliran
function GetFieldValue(ARecordNo, FieldNo: Integer): string; //Konten bidang
publik
Buat Konstruktor (Pemilik: TComponent);
Penghancuran Destruktor;
prosedur Buka; //Buat aliran untuk bersiap menyimpan data
procedure SaveToFile(ADataSet: TDataSet; AFileName: string); //Metode penyimpanan
prosedur LoadFromFile(AFileName: string); //Muat data
procedure FieldStream(ARecordNo, FieldNo: Integer; var AStream: TStream);
properti Nama Bidang[Indeks: Integer]: string dibaca GetFieldName; //nama bidang
properti FieldDataTypes[Indeks: Integer]: TFieldType baca GetFieldDataType;
properti FieldDisplayLabels[Indeks: Integer]: string dibaca GetDisplayLabel;
properti Bidang[RecNo, FieldIndex: Integer]: string dibaca GetFieldValue;
//properti FieldStreams[RecNo, FieldIndex: Integer]: TStream baca GetFieldStream;
properti RecordCount: Integer baca FRecordCount tulis FRecordCount;
properti FieldCount: Integer baca FFieldCount tulis FFieldCount;
diterbitkan
properti RptTitle: string baca FRptTitle tulis FRptTitle;
properti PageHead: string baca FPageHead tulis FPageHead;
properti PageFoot: string baca FPageFoot tulis FPageFoot;
akhir;
fungsi ReadAChar(AStream: TStream): Char;
fungsi ReadAStr(AStream: TStream): string;
fungsi ReadBStr(AStream: TStream; Ukuran: Integer): string;
fungsi ReadAInteger(AStream: TStream): Integer;
prosedur WriteAStr(AStream: TStream; AStr: string);
prosedur WriteBStr(AStream: TStream; AStr: string);
prosedur WriteAInteger(AStream: TStream; AInteger: Integer);
prosedur Daftar;
pelaksanaan
prosedur Daftar;
mulai
RegisterComponents('Akses data', [TIbStorage]);
akhir;
fungsi ReadAChar(AStream: TStream): Char;
Var
AChar: Arang;
mulai
AStream.Baca(AChar, 1);
Hasil := AChar;
akhir;
fungsi ReadAStr(AStream: TStream): string;
var
Str: Tali;
C:Karakter;
mulai
Str := '';
C := BacaAChar(AStream);
Sementara C <> #0 lakukan
mulai
Str := Str + C;
C := BacaAChar(AStream);
akhir;
Hasil := Str;
akhir;
fungsi ReadBStr(AStream: TStream; Ukuran: Integer): string;
var
Str: Tali;
C:Karakter;
Saya : Bilangan Bulat;
mulai
Str := '';
Untuk I := 1 untuk ukuran do
mulai
C := BacaAChar(AStream);
Str := Str + C;
akhir;
Hasil := Str;
akhir;
fungsi ReadAInteger(AStream: TStream): Integer;
var
Str: Tali;
C:Karakter;
mulai
Hasil := MaxInt;
Str := '';
C := BacaAChar(AStream);
Sementara C <> #0 lakukan
mulai
Str := Str + C;
C := BacaAChar(AStream);
akhir;
mencoba
Hasil := StrToInt(Str);
kecuali
application.MessageBox('String saat ini tidak dapat dikonversi ke bilangan bulat!', 'Kesalahan',
Mb_Ok + Mb_IconError);
akhir;
akhir;
prosedur WriteAStr(AStream: TStream; AStr: string);
mulai
AStream.Write(Pointer(AStr)^, Panjang(AStr) + 1);
akhir;
prosedur WriteBStr(AStream: TStream; AStr: string);
mulai
AStream.Write(Pointer(AStr)^, Panjang(AStr));
akhir;
prosedur WriteAInteger(AStream: TStream; AInteger: Integer);
var
S: tali;
mulai
S := IntToStr(AInteger);
WriteAstr(AStream, S);
akhir;
Konstruktor TIbStorage.Create(Pemilik: TComponent);
mulai
Warisan Buat(Pemilik);
FOpenFlag := False; //Tandai untuk menentukan apakah aliran telah dibuat
akhir;
Penghancur TIbStorage.Destroy;
mulai
jika FOpenFlag maka
mulai
FStream.Gratis;
FStreamIndex.Gratis;
FFielNames.Gratis;
akhir;
Kehancuran yang diwariskan;
akhir;
prosedur TIbStorage.Open;
mulai
FOpenFlag := Benar;
FStream := TMemoryStream.Buat;
FStreamIndex := TStringList.Buat;
NamaField := TStringList.Buat;
Mengatur ulang;
akhir;
prosedur TIbStorage.Reset; //reset
mulai
jika FOpenFlag maka
mulai
FFieldNames.Clear;
FStreamIndex.Hapus;
FStream.Ukuran := 0;
Judul FRpt := '';
FPageHead := '';
FPageFoot := '';
Jumlah Bidang := 0;
Jumlah Catatan F := 0;
akhir;
akhir;
//-------Simpan bagian data
prosedur TIbStorage.SaveToFile(ADataSet: TDataSet; AFileName: string);
var
Fp: TFileStream;
Saya : Bilangan Bulat;
Bab: Char;
T1, T2: TDateTime;
Str: tali;
mulai
jika Bukan FOpenFlag maka
mulai
showmessage('Objek tidak terbuka');
KELUAR;
akhir;
mencoba
jika FileExists(AFileName) maka DeleteFile(AFileName);
Fp := TFileStream.Create(AFileName, fmCreate);
Mengatur ulang;
SaveHead(ADataSet, Fp); //Simpan informasi header---Instruksi tambahan
IndexFields(ADataSet); //Simpan informasi lapangan dari kumpulan data ke FFieldName
LoadTableToStream(ADataSet); //Menyimpan informasi data dari kumpulan data
WriteAStr(Fp, FFieldNames.Text); //Informasi nama kolom penyimpanan
Ch := '@';
Fp.Write(Bab, 1);
WriteAStr(Fp, FStreamIndex.Text); //Daftar indeks bidang penyimpanan
Ch := '@';
Fp.Write(Bab, 1);
Fp.CopyFrom(FStream, 0);
Akhirnya
Fp.Gratis;
akhir;
akhir;
prosedur TIbStorage.SaveHead(ADataSet: TDataSet; Fp: TStream);
Var
Saya : Bilangan Bulat;
Bab: Char;
mulai
jika Bukan ADataSet.Active maka ADataSet.Active := True;
WriteAStr(Fp, Bendera);
WriteAStr(Fp, FRptJudul);
WriteAStr(Fp, FPageHead);
WriteAStr(Fp, FPageFoot);
FFieldCount := ADataSet.Fields.Count;
FRecordCount := ADataSet.RecordCount;
WriteAStr(Fp, IntToStr(ADataSet.Fields.Count));
WriteAStr(Fp, IntToStr(ADataSet.RecordCount));
Ch := '@';
Fp.Write(Bab, 1);
akhir;
prosedur TIbStorage.IndexFields(ADataSet: TDataSet);
var
Saya : Bilangan Bulat;
Bidang: Bidang;
mulai
Untuk I := 0 hingga ADataSet.Fields.Count - 1 lakukan
mulai
Bidang := ADataSet.Fields[I];
//Tidak menggunakan FFieldNames.Values[AField.FieldName] := AField.DisplayLabel berarti mempertimbangkan efisiensi
FFieldNames.Add(AField.FieldName + '=' + AFfield.DisplayLabel);
FFieldNames.Add(AField.FieldName + 'DataType=' + IntToStr(Ord(AField.DataType)));
akhir;
akhir;
prosedur TIbStorage.LoadTableToStream(ADataSet: TDataSet);
var
Tidak: Bilangan Bulat;
I, J, Ukuran: Integer;
Tmp, Id, Str : string; //id=string(RecNO) + string(NoField)
Len: Bilangan Bulat;
Bab: Char;
Aliran Blob: TBlobStream;
mulai
jika Bukan FOpenFlag maka
mulai
showmessage('Objek tidak terbuka');
KELUAR;
akhir;
mencoba
ADataSet.DisableControls;
ADDataSet.Pertama;
Tidak := 0;
FStreamIndex.Hapus;
FStream.Ukuran := 0;
Meskipun Bukan ADataSet.Eof lakukan
mulai
Tidak := Tidak + 1;
Untuk J := 0 hingga ADataSet.Fields.Count - 1 lakukan
mulai
Id := Inttostr(TIDAK) + '_' + IntToStr(J);
//Buat indeks posisi aliran, indeks mengarah ke: Ukuran#0Konten
FStreamIndex.Add(Id + '=' + IntToStr(FStream.Position));
//Menyimpan informasi bidang ke dalam aliran
SaveFieldToStream(FStream, ADataSet.Fields[J]);
akhir;
ADDataSet.Berikutnya;
akhir;
Akhirnya
ADDataSet.EnableControls;
akhir;
akhir;
//Jika konten bidang saat ini kosong atau BlobSize<=0, hanya ukuran bidang yang 0 dan tidak ada konten yang ditulis.
prosedur TIbStorage.SaveFieldToStream(AStream: TStream; AFfield: TField);
var
Ukuran: Bilangan Bulat;
Bab: Char;
XF: TSaliran;
Str: tali;
mulai
jika AField.IsBlob lalu
mulai
//Cara menyimpan konten bidang TBlobField sebagai aliran
Xf := TBlobStream.Create(TBlobField(AFfield), bmread);
mencoba
jika Xf.Size > 0 maka
mulai
Ukuran := Xf.Ukuran;
WriteAInteger(AStream, Ukuran);
AStream.CopyFrom(Xf, Xf.Ukuran);
akhir
kalau tidak
WriteAInteger(AStream, 0);
Akhirnya
XF.Gratis;
akhir;
akhir
kalau tidak
mulai
Str := AField.AsString;
Ukuran := Panjang(Str);
WriteAInteger(AStream, Ukuran);
jika Ukuran <> 0 maka
AStream.Write(Pointer(Str)^, Ukuran);
//WriteAstr(AStream, Str);
akhir;
Ch := '@';
AStream.Write(Bab, 1);
akhir;
//------------Muat Data
prosedur TIbStorage.LoadFromFile(AFileName: string);
var
Fp: TFileStream;
Periksa: tali;
mulai
Mengatur ulang;
mencoba
jika Bukan FileExists(AFileName) maka
mulai
showmessage('File tidak ada:' + AFileName);
KELUAR;
akhir;
Fp := TFileStream.Create(AFileName, fmOpenRead);
Periksa := ReadAStr(Fp);
jika Centang <> Tandai lalu
mulai
Application.MessageBox('Format file ilegal', 'Kesalahan', Mb_Ok + Mb_IconError);
KELUAR;
akhir;
DapatkanKepala(Fp);
DapatkanNamaField(Fp);
DapatkanIndeks(Fp);
FStream.CopyFrom(Fp, Fp.Ukuran-Fp.Posisi);
Akhirnya
Fp.Gratis;
akhir;
akhir;
prosedur TIbStorage.GetHead(Fp: TFileStream);
mulai
Judul FRpt := ReadAStr(Fp);
FPageHead := BacaAstr(Fp);
FPageFoot := ReadAstr(Fp);
FFieldCount := ReadAInteger(Fp);
FRecordCount := ReadAInteger(Fp);
jika ReadAChar(Fp) <> '@' lalu showmessage('GetHead File Error');
akhir;
prosedur TIbStorage.GetFieldNames(Fp: TFileStream);
var
Bab: Char;
Str: tali;
mulai
Str := '';
Str := BacaAStr(Fp);
FFieldNames.CommaText := Str;
Ch := BacaAChar(Fp);
if Ch <> '@' kemudian Showmessage('Ketika mendapatkan nama field Error');
akhir;
prosedur TIbStorage.GetIndex(Fp: TFileStream);
var
Bab: Char;
Str: tali;
mulai
Str := '';
Str := BacaAStr(Fp);
FStreamIndex.CommaText := Str;
Ch := BacaAChar(Fp);
if Ch <> '@' kemudian Showmessage('Ketika Mendapatkan Kesalahan Indeks Posisi Lapangan');
akhir;
//---------Baca Bagian Nilai Bidang
fungsi TIbStorage.GetFieldValue(ARecordNo, FieldNo: Integer): string;
var
Id, T : tali;
Pos: Bilangan Bulat;
Len, Saya : Integer;
Er: Boolean;
mulai
Hasil := '';
Eh := Salah;
jika ARecordNo > FRecordCount lalu
Er := benar; //ARecordNo := FRecordCount;
jika ARecordNo < 1 maka
Er := Benar; // Nomor Catatan := 1;
jika FieldNo >= FFieldCount maka
Er := Benar; //Nomor Bidang :=Jumlah Bidang - 1;
ifFieldNo < 0 maka
Eh := Benar; //NoField := 0;
jika Er maka
mulai
Showmessage('Nomor rekaman atau label kolom di luar batas');
KELUAR;
akhir;
jika FFieldCount = 0 maka Keluar;
Id := Inttostr(ARecordNO) + '_' + IntToStr(FieldNo);
Pos := StrToInt(FStreamIndex.Values[Id]);
FStream.Posisi := Pos;
//Mendapatkan panjang isi field
Len := ReadAInteger(FStream);
jika Len > 0 maka
Hasil := ReadBStr(FStream, Len);
jika ReadAChar(FStream) <> '@' lalu
Showmessage('Ketika Bidang Dibaca, Temukan Kesalahan Format Simpan');
akhir;
prosedur TIbStorage.FieldStream(ARecordNo, FieldNo: Integer; var AStream: TStream);
var
Id, T : tali;
Pos: Bilangan Bulat;
Len, Saya : Integer;
Er: Boolean;
mulai
Eh := Salah;
jika ARecordNo > FRecordCount lalu
Er := benar; //ARecordNo := FRecordCount;
jika ARecordNo < 1 maka
Er := Benar; // Nomor Catatan := 1;
jika FieldNo >= FFieldCount maka
Er := Benar; //Nomor Bidang :=Jumlah Bidang - 1;
ifFieldNo < 0 maka
Eh := Benar; //NoField := 0;
jika Er maka
mulai
TDsException.Create('Subskrip fungsi GetFieldValue di luar batas');
KELUAR;
akhir;
jika FFieldCount = 0 maka Keluar;
Id := Inttostr(ARecordNO) + IntToStr(FieldNo);
Pos := StrToInt(FStreamIndex.Values[Id]);
FStream.Posisi := Pos;
Len := ReadAInteger(FStream);
AStream.CopyFrom(FStream, Len);
akhir;
function TIbStorage.GetFieldName(AIndex: Integer): string; //Dapatkan nama field
mulai
//Bidang dan tipe data yang disimpan masing-masing berjumlah setengahnya
if ((AIndex < 0) atau (AIndex >= FFieldNames.Count div 2)) maka
Application.MessageBox('Indeks nama bidang di luar batas', 'Kesalahan program',
Mb_Ok + Mb_IconError)
kalau tidak
Hasil := FFieldNames.Names[AIndex*2];
akhir;
function TIbStorage.GetFieldDataType(AIndex: Integer): TFieldType; //Dapatkan nama field
mulai
//Bidang dan tipe data yang disimpan masing-masing berjumlah setengahnya
if ((AIndex < 0) atau (AIndex >= FFieldNames.Count div 2)) maka
Application.MessageBox('Indeks tipe data bidang di luar batas', 'Kesalahan program',
Mb_Ok + Mb_IconError)
kalau tidak
Hasil := TFieldType(StrToInt(FFieldNames.Values[FFieldNames.Names[AIndex*2+1]]));
akhir;
function TIbStorage.GetDisplayLabel(AIndex: Integer): string; //Dapatkan nama tampilan bidang
mulai
jika ((AIndex < 0) atau (AIndex >= FFieldNames.Count)) maka
Application.MessageBox('Indeks nama bidang di luar batas', 'Kesalahan program',
Mb_Ok + Mb_IconError)
kalau tidak
Hasil := FFieldNames.Values[GetFieldName(AIndex)];
akhir;
akhir.
Melalui pengujian, kontrol ini memiliki dukungan yang baik untuk kontrol kumpulan data yang umum digunakan seperti Ttable, Tquery, TaodTable, TadoQuery, TibTable, TibQuery, dll., dan memiliki efisiensi yang baik (pengujian: 1100 catatan personel, 23 bidang disimpan sebagai file membutuhkan waktu sekitar 2 detik).
4. Penggunaan kontrol dasar
1. Menyimpan data dari kumpulan data ke file
IbStorage1.Open; //Buat aliran penyimpanan
IbStorage1.SaveToFile(AdadataSet, Namafile);
2. Membaca informasi data dari file
IbStorage1.Buka;
IbStorage1.LoadFromFile(AfileName);
3. Akses ke data dalam kontrol penyimpanan datagram
Nilai := IbStorage1.Fields[ArecNo, AfieldNo]; //Jenis string
Lainnya dihilangkan.
5. Kesimpulan
Dengan menulis kontrol penyimpanan datagram ini, masalah penyimpanan dan pertukaran data dalam program database dapat diselesaikan dengan lebih baik, dan kontrol praktis diberikan untuk pengembangan program database.
Kontrol melewati debugging di bawah lingkungan pengembangan Windows98 dan Delphi5.