程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 第二十章-開發Delphi對象式數據管理功能(二)(3)

第二十章-開發Delphi對象式數據管理功能(二)(3)

編輯:Delphi

20.1.7.2 TBlobStream的實現原理

說明TBlobStream對象的實現原理,不可避免地要涉及它的私有域,下面是私有域的定義:

TBlobStream = class(TStream)

private

FField: TBlobField;

FDataSet: TDataSet;

FRecord: PChar;

FBuffer: PChar;

FFieldNo: Integer;

FOpened: Boolean;

FModified: Boolean;

FPosition: Longint;

public

end;

FField是與BLOB流相聯的數據庫BLOB域,該域用於BLOB流的內部訪問。FDataSet是代表FField所在的數據庫,它可以是TTable部件,也可以是TQuery 部件。FRecord和FBuffer都是BLOB流內部使用的緩沖區,用於存儲FField所在記錄的數據,該數據記錄中不包含BLOB數據,TBlobStream使用FRecord作為調用BDE API函數的參數值。FFieldNo代表BLOB字段的字段號,也用於BDE API的參數傳遞,FOpened和FMocified都是狀態信息,FPosition表示BLOB流的當前位置,下面介紹TBlobStream方法實現。

1. Create方法和Destroy方法的實現

Create方法的功能主要是建立BlobStream流與BLOB字段的聯系並初始化某些私有變量。其實現如下:

constructor TBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);

var

OpenMode: DbiOpenMode;

begin

FField := Field;

FDataSet := Field.DataSet;

FRecord := FDataSet.ActiveBuffer;

FFieldNo := Field.FieldNo;

if FDataSet.State = dsFilter then

DBErrorFmt(SNoFieldAccess, [FField.DisplayName]);

if not FField.FModified then

begin

if Mode = bmRead then

begin

FBuffer := AllocMem(FDataSet.RecordSize);

FRecord := FBuffer;

if not FDataSet.GetCurrentRecord(FBuffer) then Exit;

OpenMode := dbiReadOnly;

end else

begin

if not (FDataSet.State in [dsEdit, dsInsert]) then DBError(SNotEditing);

OpenMode := dbiReadWrite;

end;

Check(DbiOpenBlob(FDataSet.Handle, FRecord, FFieldNo, OpenMode));

end;

FOpened := True;

if Mode = bmWrite then Truncate;

end;

該方法首先是用傳入的Field參數給FField,FDataSet,FRecord和FFieldNo賦值。方法中用AllocMem按當前記錄大小分配內存,並將指針賦給FBuffer,用DataSet部件的GetCurrentRecord方法,將記錄的值賦給FBuffer,但不包括BLOB數據。

方法中用到的DbiOpenBlob函數是BDE的API函數,該函數用於打開數據庫中的BLOB字段。

最後如果方法傳入的Mode參數值為bmWrite,就調用Truncate將當前位置指針以後的

數據刪除。

分析這段源程序不難知道:

● 讀寫BLOB字段,不允許BLOB字段所在DataSet部件有Filter,否則產生異常事件

● 要讀寫BLOB字段,必須將DataSet設為編輯或插入狀態

● 如果BLOB字段中的數據作了修改,則在創建BLOB 流時,不再重新調用DBiOpenBlob函數,而只是簡單地將FOpened置為True,這樣可以用多個BLOB 流對同一個BLOB字段讀寫

Destroy方法釋放BLOB字段和為FBuffer分配的緩沖區,其實現如下:

destructor TBlobStream.Destroy;

begin

if FOpened then

begin

if FModified then FField.FModified := True;

if not FField.FModified then

DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);

end;

if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize);

if FModified then

try

FField.DataChanged;

except

Application.HandleException(Self);

end;

end;

如果BLOB流中的數據作了修改,就將FField的FModified置為True;如果FField的Modified為False就釋放BLOB字段,如果FBuffer不為空,則釋放臨時內存。最後根據FModified的值來決定是否啟動FField的事件處理過程DataChanged。

不難看出,如果BLOB字段作了修改就不釋放BLOB字段,並且對BLOB 字段的修改只有到Destroy時才提交,這是因為讀寫BLOB字段時都避開了FField,而直接調用BDE API函數。這一點是在應用BDE API編程中很重要,即一定要修改相應數據庫部件的狀態。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved