<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      用Delphi編寫數據報存儲控件

      [摘要]一、概述 在用Delphi編寫數據庫程序時,經常涉及到數據的導入和導出操作,如:將大型數據庫中的數據存儲為便攜文件,以便于出外閱讀;將存儲在文件中的數據信息,導入到另外的數據庫中;而且,通過將數據庫...
      一、概述
      在用Delphi編寫數據庫程序時,經常涉及到數據的導入和導出操作,如:將大型數據庫中的數據存儲為便攜文件,以便于出外閱讀;將存儲在文件中的數據信息,導入到另外的數據庫中;而且,通過將數據庫中的數據存儲為數據文件,更便于程序內部和程序間交換數據,避免通過內存交換數據的煩瑣步驟,例如在筆者編寫的通用報表程序中即以該控件作為數據信息傳遞的載體。
      二、基本思路
      作為數據報存儲控件,應能夠存儲和讀入數據集的基本信息(如:字段名,字段的顯示名稱,字段的數據類型,記錄數,字段數,指定記錄指定字段的當前值等),應能夠提供較好的封裝特性,以便于使用。
      基于此,筆者利用Delphi5.0面向對象的特點,設計開發了數據報存儲控件。
      三、實現方法
      編寫如下代碼單元:
      unit IbDbFile;
      interface
      Uses Windows, SysUtils, Classes, Forms, Db, DbTables, Dialogs;
      Const
      Flag = '數據報-吉星軟件工作室';
      Type
      TDsException = Class(Exception);
      TIbStorage = class(TComponent)
      private
      FRptTitle: string; //存儲數據報說明
      FPageHead: string; //頁頭說明
      FPageFoot: string; //爺腳說明
      FFieldNames: TStrings; //字段名表
      FStreamIndex: TStrings; //字段索引
      FStream: TStream; //存儲字段內容的流
      FFieldCount: Integer; //字段數
      FRecordCount: Integer; //記錄數
      FOpenFlag: Boolean; //流是否創建標志
      protected
      procedure Reset; //復位---清空流的內容
      procedure SaveHead(ADataSet: TDataSet; Fp: TStream); //存儲報表頭信息
      procedure LoadTableToStream(ADataSet: TDataSet); //存儲記錄數據
      procedure IndexFields(ADataSet: TDataSet); //將數據集的字段名保存到列表中
      procedure GetHead(Fp: TFileStream); //保存報表頭信息
      procedure GetIndex(Fp: TFileStream); //建立記錄流索引
      procedure GetFieldNames(Fp: TFileStream); //從流中讀入字段名表
      function GetFieldName(AIndex: Integer): string; //取得字段名稱
      function GetFieldDataType(AIndex: Integer): TFieldType;
      function GetDisplayLabel(AIndex: Integer): string; //取得字段顯示名稱
      procedure SaveFieldToStream(AStream: TStream; AField: TField); //將字段存入流中
      function GetFieldValue(ARecordNo, FieldNo: Integer): string; //字段的內容
      public
      Constructor Create(AOwner: TComponent);
      Destructor Destroy; override;
      procedure Open; //創建流以準備存儲數據
      procedure SaveToFile(ADataSet: TDataSet; AFileName: string); //存儲方法
      procedure LoadFromFile(AFileName: string); //裝入數據
      procedure FieldStream(ARecordNo, FieldNo: Integer; var AStream: TStream);
      property FieldNames[Index: Integer]: string read GetFieldName; //字段名
      property FieldDataTypes[Index: Integer]: TFieldType read GetFieldDataType;
      property FieldDisplayLabels[Index: Integer]: string read GetDisplayLabel;
      property Fields[RecNo, FieldIndex: Integer]: string read GetFieldValue;
      //property FieldStreams[RecNo, FieldIndex: Integer]: TStream read GetFieldStream;
      property RecordCount: Integer read FRecordCount write FRecordCount;
      property FieldCount: Integer read FFieldCount write FFieldCount;
      published
      property RptTitle: string read FRptTitle write FRptTitle;
      property PageHead: string read FPageHead write FPageHead;
      property PageFoot: string read FPageFoot write FPageFoot;
      end;

      function ReadAChar(AStream: TStream): Char;
      function ReadAStr(AStream: TStream): string;
      function ReadBStr(AStream: TStream; Size: Integer): string;
      function ReadAInteger(AStream: TStream): Integer;
      procedure WriteAStr(AStream: TStream; AStr: string);
      procedure WriteBStr(AStream: TStream; AStr: string);
      procedure WriteAInteger(AStream: TStream; AInteger: Integer);

      procedure Register;
      implementation

      procedure Register;
      begin
      RegisterComponents('Data Access', [TIbStorage]);
      end;

      function ReadAChar(AStream: TStream): Char;
      Var
      AChar: Char;
      begin
      AStream.Read(AChar, 1);
      Result := AChar;
      end;

      function ReadAStr(AStream: TStream): string;
      var
      Str: String;
      C : Char;
      begin
      Str := '';
      C := ReadAChar(AStream);
      While C <> #0 do
      begin
      Str := Str + C;
      C := ReadAChar(AStream);
      end;
      Result := Str;
      end;

      function ReadBStr(AStream: TStream; Size: Integer): string;
      var
      Str: String;
      C : Char;
      I : Integer;
      begin
      Str := '';
      For I := 1 to Size do
      begin
      C := ReadAChar(AStream);
      Str := Str + C;
      end;
      Result := Str;
      end;

      function ReadAInteger(AStream: TStream): Integer;
      var
      Str: String;
      C : Char;
      begin
      Result := MaxInt;
      Str := '';
      C := ReadAChar(AStream);
      While C <> #0 do
      begin
      Str := Str + C;
      C := ReadAChar(AStream);
      end;
      try
      Result := StrToInt(Str);
      except
      Application.MessageBox(' 當前字符串無法轉換為整數!', '錯誤',
      Mb_Ok + Mb_IconError);
      end;
      end;


      procedure WriteAStr(AStream: TStream; AStr: string);
      begin
      AStream.Write(Pointer(AStr)^, Length(AStr) + 1);
      end;

      procedure WriteBStr(AStream: TStream; AStr: string);
      begin
      AStream.Write(Pointer(AStr)^, Length(AStr));
      end;

      procedure WriteAInteger(AStream: TStream; AInteger: Integer);
      var
      S : string;
      begin
      S := IntToStr(AInteger);
      WriteAstr(AStream, S);
      end;

      Constructor TIbStorage.Create(AOwner: TComponent);
      begin
      inherited Create(AOwner);
      FOpenFlag := False; //確定流是否創建的標志
      end;

      Destructor TIbStorage.Destroy;
      begin
      if FOpenFlag then
      begin
      FStream.Free;
      FStreamIndex.Free;
      FFieldNames.Free;
      end;
      inherited Destroy;
      end;

      procedure TIbStorage.Open;
      begin
      FOpenFlag := True;
      FStream := TMemoryStream.Create;
      FStreamIndex := TStringList.Create;
      FFieldNames := TStringList.Create;
      Reset;
      end;

      procedure TIbStorage.Reset; //復位
      begin
      if FOpenFlag then
      begin
      FFieldNames.Clear;
      FStreamIndex.Clear;
      FStream.Size := 0;
      FRptTitle := '';
      FPageHead := '';
      FPageFoot := '';
      FFieldCount := 0;
      FRecordCount := 0;
      end;
      end;

      //-------保存數據部分
      procedure TIbStorage.SaveToFile(ADataSet: TDataSet; AFileName: string);
      var
      Fp: TFileStream;
      I : Integer;
      Ch: Char;
      T1, T2: TDateTime;
      Str: string;
      begin
      if Not FOpenFlag then
      begin
      showmessage(' 對象沒有打開');
      Exit;
      end;
      try
      if FileExists(AFileName) then DeleteFile(AFileName);
      Fp := TFileStream.Create(AFileName, fmCreate);
      Reset;
      SaveHead(ADataSet, Fp); //保存頭部信息---附加說明
      IndexFields(ADataSet); //將數據集的字段信息保存到FFieldName
      LoadTableToStream(ADataSet); //保存數據集的數據信息
      WriteAStr(Fp, FFieldNames.Text); //存儲字段名信息
      Ch := '@';
      Fp.Write(Ch, 1);
      WriteAStr(Fp, FStreamIndex.Text); //存儲字段索引列表
      Ch := '@';
      Fp.Write(Ch, 1);
      Fp.CopyFrom(FStream, 0);
      finally
      Fp.Free;
      end;
      end;

      procedure TIbStorage.SaveHead(ADataSet: TDataSet; Fp: TStream);
      Var
      I : Integer;
      Ch: Char;
      begin
      if Not ADataSet.Active then ADataSet.Active := True;
      WriteAStr(Fp, Flag);
      WriteAStr(Fp, FRptTitle);
      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(Ch, 1);
      end;

      procedure TIbStorage.IndexFields(ADataSet: TDataSet);
      var
      I : Integer;
      AField: TField;
      begin
      For I := 0 to ADataSet.Fields.Count - 1 do
      begin
      AField := ADataSet.Fields[I];
      //不用FFieldNames.Values[AField.FieldName] := AField.DisplayLabel;是考慮效率
      FFieldNames.Add(AField.FieldName + '=' + AField.DisplayLabel);
      FFieldNames.Add(AField.FieldName + 'DataType=' + IntToStr(Ord(AField.DataType)));
      end;
      end;

      procedure TIbStorage.LoadTableToStream(ADataSet: TDataSet);
      var
      No: Integer;
      I, J, Size: Integer;
      Tmp, Id, Str : string; //id=string(RecNO) + string(FieldNo)
      Len: Integer;
      Ch : Char;
      BlobStream: TBlobStream;
      begin
      if Not FOpenFlag then
      begin
      showmessage(' 對象沒有打開');
      Exit;
      end;
      try
      ADataSet.DisableControls;
      ADataSet.First;
      No := 0;
      FStreamIndex.Clear;
      FStream.Size := 0;
      While Not ADataSet.Eof do
      begin
      No := No + 1;
      For J := 0 to ADataSet.Fields.Count - 1 do
      begin
      Id := Inttostr(NO) + '_' + IntToStr(J);
      //建立流的位置的索引, 索引指向: Size#0Content
      FStreamIndex.Add(Id + '=' + IntToStr(FStream.Position));
      //存儲字段信息到流中
      SaveFieldToStream(FStream, ADataSet.Fields[J]);
      end;
      ADataSet.Next;
      end;
      finally
      ADataSet.EnableControls;
      end;
      end;

      //如果一個字段的當前內容為空或者BlobSize<=0,則只寫入字段大小為0, 不寫入內容
      procedure TIbStorage.SaveFieldToStream(AStream: TStream; AField: TField);
      var
      Size: Integer;
      Ch: Char;
      XF: TStream;
      Str: string;
      begin
      if AField.IsBlob then
      begin
      //如何把一個TBlobField字段的內容存儲為流
      Xf := TBlobStream.Create(TBlobField(AField), bmread);
      try
      if Xf.Size > 0 then
      begin
      Size := Xf.Size;
      WriteAInteger(AStream, Size);
      AStream.CopyFrom(Xf, Xf.Size);
      end
      else
      WriteAInteger(AStream, 0);
      finally
      XF.Free;
      end;
      end
      else
      begin
      Str := AField.AsString;
      Size := Length(Str);
      WriteAInteger(AStream, Size);
      if Size <> 0 then
      AStream.Write(Pointer(Str)^, Size);
      //WriteAstr(AStream, Str);
      end;
      Ch := '@';
      AStream.Write(Ch, 1);
      end;

      //------------Load Data
      procedure TIbStorage.LoadFromFile(AFileName: string);
      var
      Fp: TFileStream;
      Check: string;
      begin
      Reset;
      try
      if Not FileExists(AFileName) then
      begin
      showmessage(' 文件不存在:' + AFileName);
      Exit;
      end;
      Fp := TFileStream.Create(AFileName, fmOpenRead);
      Check := ReadAStr(Fp);
      if Check <> Flag then
      begin
      Application.MessageBox(' 非法文件格式', '錯誤', Mb_Ok + Mb_IconError);
      Exit;
      end;
      GetHead(Fp);
      GetFieldNames(Fp);
      GetIndex(Fp);
      FStream.CopyFrom(Fp, Fp.Size-Fp.Position);
      finally
      Fp.Free;
      end;
      end;

      procedure TIbStorage.GetHead(Fp: TFileStream);
      begin
      FRptTitle := ReadAStr(Fp);
      FPageHead := ReadAstr(Fp);
      FPageFoot := ReadAstr(Fp);
      FFieldCount := ReadAInteger(Fp);
      FRecordCount := ReadAInteger(Fp);
      if ReadAChar(Fp) <> '@' then showmessage('GetHead File Error');
      end;

      procedure TIbStorage.GetFieldNames(Fp: TFileStream);
      var
      Ch: Char;
      Str: string;
      begin
      Str := '';
      Str := ReadAStr(Fp);
      FFieldNames.CommaText := Str;
      Ch := ReadAChar(Fp);
      if Ch <> '@' then Showmessage('When get fieldnames Error');
      end;

      procedure TIbStorage.GetIndex(Fp: TFileStream);
      var
      Ch: Char;
      Str: string;
      begin
      Str := '';
      Str := ReadAStr(Fp);
      FStreamIndex.CommaText := Str;
      Ch := ReadAChar(Fp);
      if Ch <> '@' then Showmessage('When Get Field Position Index Error');
      end;

      //---------Read Field's Value Part
      function TIbStorage.GetFieldValue(ARecordNo, FieldNo: Integer): string;
      var
      Id, T : string;
      Pos: Integer;
      Len, I : Integer;
      Er: Boolean;
      begin
      Result := '';
      Er := False;
      if ARecordNo > FRecordCount then
      Er := true; //ARecordNo := FRecordCount;
      if ARecordNo < 1 then
      Er := True; // ARecordNo := 1;
      if FieldNo >= FFieldCount then
      Er := True; // FieldNo := FFieldCount - 1;
      if FieldNo < 0 then
      Er := True; //FieldNo := 0;
      if Er then
      begin
      Showmessage('記錄號或者字段標號越界');
      Exit;
      end;
      if FFieldCount = 0 then Exit;
      Id := Inttostr(ARecordNO) + '_' + IntToStr(FieldNo);
      Pos := StrToInt(FStreamIndex.Values[Id]);
      FStream.Position := Pos;
      //取得字段內容的長度
      Len := ReadAInteger(FStream);
      if Len > 0 then
      Result := ReadBStr(FStream, Len);
      if ReadAChar(FStream) <> '@' then
      Showmessage('When Read Field, Find Save Format Error');
      end;

      procedure TIbStorage.FieldStream(ARecordNo, FieldNo: Integer; var AStream: TStream);
      var
      Id, T : string;
      Pos: Integer;
      Len, I : Integer;
      Er: Boolean;
      begin
      Er := False;
      if ARecordNo > FRecordCount then
      Er := true; //ARecordNo := FRecordCount;
      if ARecordNo < 1 then
      Er := True; // ARecordNo := 1;
      if FieldNo >= FFieldCount then
      Er := True; // FieldNo := FFieldCount - 1;
      if FieldNo < 0 then
      Er := True; //FieldNo := 0;
      if Er then
      begin
      TDsException.Create('GetFieldValue函數索引下標越界');
      Exit;
      end;
      if FFieldCount = 0 then Exit;
      Id := Inttostr(ARecordNO) + IntToStr(FieldNo);
      Pos := StrToInt(FStreamIndex.Values[Id]);
      FStream.Position := Pos;
      Len := ReadAInteger(FStream);
      AStream.CopyFrom(FStream, Len);
      end;

      function TIbStorage.GetFieldName(AIndex: Integer): string; //取得字段名稱
      begin
      //存儲的字段和數據類型各占一半
      if ((AIndex < 0) or (AIndex >= FFieldNames.Count div 2)) then
      Application.MessageBox(' 取字段名索引越界', '程序 錯誤',
      Mb_Ok + Mb_IconError)
      else
      Result := FFieldNames.Names[AIndex*2];
      end;

      function TIbStorage.GetFieldDataType(AIndex: Integer): TFieldType; //取得字段名稱
      begin
      //存儲的字段和數據類型各占一半
      if ((AIndex < 0) or (AIndex >= FFieldNames.Count div 2)) then
      Application.MessageBox(' 取字段數據類型索引越界', '程序 錯誤',
      Mb_Ok + Mb_IconError)
      else
      Result := TFieldType(StrToInt(FFieldNames.Values[FFieldNames.Names[AIndex*2+1]]));
      end;

      function TIbStorage.GetDisplayLabel(AIndex: Integer): string; //取得字段顯示名稱
      begin
      if ((AIndex < 0) or (AIndex >= FFieldNames.Count)) then
      Application.MessageBox(' 取字段名索引越界', '程序 錯誤',
      Mb_Ok + Mb_IconError)
      else
      Result := FFieldNames.Values[GetFieldName(AIndex)];
      end;

      end.
      通過測試,該控件對Ttable,Tquery, TaodTable, TadoQuery, TibTable, TibQuery等常用的數據集控件等都能較好的支持,并且具有較好的效率(測試:1100條人事記錄,23個字段存儲為文件約用時2秒鐘)。

      四、控件的基本使用方法
      1.存儲數據集中的數據到文件
      IbStorage1.Open; //創建存儲流
      IbStorage1.SaveToFile(AdataSet, Afilename);
      2.從文件中讀出數據信息
      IbStorage1.Open;
      IbStorage1.LoadFromFile(AfileName);
      3.對數據報存儲控件中數據的訪問
      Value := IbStorage1.Fields[ArecNo, AfieldNo]; //字符串類型
      其它略。
      五、結束語
      通過編寫此數據報存儲控件,較好地解決了數據庫程序中數據的存儲和交換問題,為數據庫程序的開發提供了一種實用的控件。
      該控件在Windows98,Delphi5開發環境下調試通過。


      日韩精品一区二区三区高清