首页 / 软件开发 / Delphi / 第二十章-开发Delphi对象式数据管理功能(二)(3)
第二十章-开发Delphi对象式数据管理功能(二)(3)2007-05-0720.1.7.2 TBlobStream的实现原理说明TBlobStream对象的实现原理,不可避免地要涉及它的私有域,下面是私有域的定义:TBlobStream = class(TStream)privateFField: TBlobField;FDataSet: TDataSet;FRecord: PChar;FBuffer: PChar;FFieldNo: Integer;FOpened: Boolean;FModified: Boolean;FPosition: Longint;publicend;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);varOpenMode: DbiOpenMode;beginFField := Field;FDataSet := Field.DataSet;FRecord := FDataSet.ActiveBuffer;FFieldNo := Field.FieldNo;if FDataSet.State = dsFilter thenDBErrorFmt(SNoFieldAccess, [FField.DisplayName]);if not FField.FModified thenbeginif Mode = bmRead thenbeginFBuffer := AllocMem(FDataSet.RecordSize);FRecord := FBuffer;if not FDataSet.GetCurrentRecord(FBuffer) then Exit;OpenMode := dbiReadOnly;end elsebeginif 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;beginif FOpened thenbeginif FModified then FField.FModified := True;if not FField.FModified thenDbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);end;if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize);if FModified thentryFField.DataChanged;exceptApplication.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编程中很重要,即一定要修改相应数据库部件的状态。