网站首页

家园论坛

老版论坛

家园博客

业界新闻

技术文档

下载中心

速查中心

图片中心

硬件资讯
上一篇:第二十章 开发Delphi对象式数据管理功能(三) 下一篇:第二十章 开发Delphi对象式数据管理功能(五)
第二十章 开发Delphi对象式数据管理功能(四)

来源: 作者: 添加日期:2005-9-4 19:19:56 点击次数:

20.2.3 TReader对象 

  TReader对象是可实例化的用于从相联系的流中读取数据的Filer对象。TReader对象从TFiler继承下来,除了从TFiler继承的属性和方法外,TReader声明了不少属性、方法和事件。

  OwnerParent属性用于表示从Reader对象的流中读取的部件的拥有者和双亲结点。onErrorOnFindMethodOnSetName事件使应用程序在运行中读数据时能定制响应方式。除了覆盖了一些从TFiler对象中继承的方法外,TReader对象还定义大量的读不同类型的数据和触发事件的方法。 

20.2.3.1 TReader对象的属性和方法 

  1. Owner属性

  声明:property Owner: TComponent;

Reader对象的Owner属性存储了将用来给从Reader的流中读出的部件的Owner属性赋值的部件。

  2. Parent属性

  声明:property Parent: TComponent;

Parent属性存储将用来给从Reader的流中读出所有控制的Parent属性赋值的部件。

  3. Position属性

  声明:propertion: Longint;

Reader对象的Position属性表示相联的流中读的当前位置。Position的值还应包括读缓冲区的大小。对于Reader 对象,Position的值大于流的Position 的值。如果将Position的值设得超过当前缓冲区,将引起调用FlushBuffer

  4. BeginReferences方法

  声明:procedure BeginReferences;

BeginReferences方法启动一连串关于读部件的命令,这些部件包含相互间的交叉引用。在使用上通常和FixupReferencesEndReferences一起放在Tryfinally程序块中。

  在调用了BeginReferences后,Reader对象创建读取所有对象和名字的列表。所有的独立对象被读出后,调用FixupReferences方法将名字的相互从流中转移到对象实例中。最后调用EndReferences方法释放列表。

  处理部件相互引用的程序块形式如下: 

BeginReferences; { 创建临时列表 }

try

{ 读出所有部件并将它们的名字放在一临时列表中 }

FixupReferences; { }

finally

EndReferences; { 释放临时列表 }

end; 

  5. FixUpReferences方法

  声明:procedure FixupReferences;

FixupReferences方法分解从流中读出的存在各种相互依赖部件的引用关系。FixupReferences总在tryfinally块中并配合BeginReferencesEndReferences一起使用。

  6. EndReferences方法

  声明:procedure EndReferences;

EndReferences方法终止处理相互引用的块操作,释放对象列表。它总配合BeginReferencesFixupReferences一起使用。

  7. ReadListBegin方法

  声明:procedure ReadListBegin;

ReadListBegin方法从Reader对象相联的流中读取列表开始标志。如果流中紧接着要读取的项目不是一个由WritelistBegin方法写入的列表起始标志,ReadListBegin将引起一个读异常事件。

  通常在调用ReadlistBegin方法之后,紧跟着一个读项目的循环,循环以EndfList方法返回True 终止条件。这时,预示流中的下一个项目是列表结束标志,需要调用ReadListEnd方法。

  8. ReadListEnd方法

  声明:procedure ReadListEnd;

ReadListEnd 方法从流中读取列表结束标志。如果所读的项目不是一个列表结束标志,ReadListEnd方法引发一个EReadError异常事件。

  9. EndOfList方法

  声明:function EndOfList: Boolean;

如果Reader对象读到项目列表结果标志,EndOfList方法返回True

  TStrings对象在从Reader对象读取项目列表时使用了ReadListBeginReadListEnd方法。下面的ReadDataTStrings的方法,用于在DefineProperties方面中读string数据。 

procedure TStrings.ReadData(Reader: TReader);

begin

Reader.ReadListBegin; { 读列表开始标志 }

Clear; { 清除已有的字符串 }

while not Reader.EndOfList do { 只要还有数据 }

Add(Reader.ReadString); { …读一个字符串并将其加在列表中 }

Reader.ReadListEnd; { 越过列表结束标志 }

end; 

10. ReadSignature方法

  声明:procedure ReadSignature;

ReadSignature方法从流中读取部件之前首先调用ReadSignature方法。在载入对象之前检测标签。Reader对象就能防止疏忽大意,导致读取无效或过时的数据。Filer标签是四个字符,对于Delphi 2.0,该标签是“TPF0”。

  11. ReadPrefix方法

  声明:procedure ReadPrefix(var Plags: TFilerFlags; var AChild, Pos: Integer);

ReadPrefix方法的功能与ReadSignature的很相象,只不过它是读取流中部件前面的标志(PreFix)。当一个Write对象将部件写入流中时,它在部件前面预写了两个值,第一个值是指明部件是否是从祖先窗体中继承的窗体和它在窗体中的位置是否重要的标志;第二个值指明它在祖先窗体创建次序。ReadComponent方法自动调用ReadPrefix。但如果需要独立读取部件的预读标志,也可直接调用该方向。

  12. OnFindMethod事件

  声明:property OnFindMethod: TFindMethodEvent;

OnFindMethod事件,发生在Reader对象读取对象的方法指针时,属性为方法指针的通常都是事件。

  响应OnFindMethod事件的理由,通常是处理过程找不到方法的情况。在FindMethod方法没有找到由Name指定的方法的情况下,如果它将OnFindMethod方法的Error 参数设为True,将引起ReadError异常事件;反之,将Error参数置为False,将防止FindMethod方法引发异常事件。

  13. Error方法

  声明:function Error(const Message: String): Boolean; virtual;

Error方法定义在Reader对象的protected部分,它是用于Reader对象的onError事件。其返回值决定是否继续错误处理过程。如果返回值为True,则表示用程序应当继续错误处理;如果返回值为False,则表示错误情况被忽略。

  如果读部件或属性出错。Reader对象调用Error方法。缺省情况下,Error将返回值设为False,然后调用onError事件处理过程。

  TReader对象总是在tryexcept程序块的except部分,并提供用户忽略错误的机会。Error的使用方法如下: 

  try

{ 读部件 }

except

on E: Exception do

begin

…{ 执行一些清除操作 }

if Error(E.Message) then raise;

end;

end;

14. onError事件

  声明:property onError: TReaderError;

Reader对象读取数据出错时将引发onError事件。通过处理onError事件,可以有选择地处理或忽略错误。

  传给onError事件处理过程的最后一个参数是名为Handledvar参数。在缺省情况下,Error方法将Handled置为True。这将阻止错误更进一步处理。如果事件处理过程仍旧将Handled置为FalseReader对象将引发一个EReadError异常事件。 

15. SetName方法

  声明:procedure SetName(Component: TComponent; var Name: String virtual);

SetName方法允许Reader对象在将从流中读取的部件的Name值赋给部件的Name属性前修改Name值。ReadComponent方法在读取部件的属性值和其它数据前先读部件的类型和名字在读完名字后,ReadComponent将所读的名字作为Name参数传给SetNameName 是个var参数,因此SetName能在返回前修改字符串值。SetName还调用了OnSetName事件处理过程,将名字字符串作为var参数传入事件处理过程中,因此,事件处理过程也可修改字符串的值。

  16. OnSetName事件

  声明:property OnSetName: TSetNameEvent;

OnSetName事件发生在Read对象设置部件的Name属性前,OnSetName事件处理过程的var参数Name参数是一个var参数,因此,事件处理过程再将Name赋给部件前,可以修改Name的值。这对于想过滤窗体中部件的名字是很有帮助的。

  下面的OnSetName事件处理过程,命名了名字中包含“Button”的部件,并用“PushButton”替代。 

procedure TForm1.ReaderSetName(Reader: TReader; Component: TComponent;

var Name: string);

var

ButtonPos: Integer;

begin

ButtonPos := Pos('Button', Name);

if ButtonPos <> 0 then

Name := Copy(Name, 1, ButtonPos - 1) + 'PushButton' +

Copy(Name, ButtonPos + 6, Length(Name));

end; 

17. ReadValue方法

  声明:function ReadValue: TValueType;

ReadValue方法读取流中紧着的项目的类型,函数返回后,流的指针移到值类型指示符之后。

  TValueType是枚举类型。存储在Filer对象的流中的每个项目之前都有一个字节标识该项目的类型,在读每个项目之前都要读取该字节,以指导调用哪个方法来闱取项目。该字节的值就TValuetype定义的值类型之一。

  18. NextValue方法

  声明:function Nextvalue: TValuetype;

Nextvalue方法的作用也是返回Reader对象流中紧接着的项目的类型,它与ReadValue的区别在于并不移动指针位置。

  19. ReadBoolean方法

  声明:function ReadBoolean: Boolean;

ReadBoolean方法从Reader对象的流中读取一个布尔值,并相应地移动流位置指针。

  20ReadChar方法

  声明:function ReadChar: char;

ReadChar方法从Reader对象的流中读取一个字符。

  21. ReadFloat方法

  声明:function ReadFloat: Extended;

  ReadFloat方法从流中读取浮点数。

  20. ReadIdent方法

  声明:function ReadIdent: string;

ReadIdent方法从流中读取标识符。

  23. ReadInteger方法

  声明:function ReadInteger: Longin

ReadInteger方法从流中读取整型数字。

24.ReadString方法

  声明:function Read String: string;

  ReadString方法从Reader对象的流中读取一个字符串,并返回字符串中的内容。该字符串是由Writer对象的WriteString方法写入。 

20.2.3.2 TReader对象的实现 

  Filer对象的作用主要是Delphi用来在DFM文件中读写各种类型的数据(包括部件对象)。这些数据的一个本质特征是变长,而且Filer对象将读写数据操作抽象化,包装成对象提供了大量的读写方法,方便了程序的调用。因此在应用程序中可以广泛使Filer对象,充分利用Delphi的面向对象技术。而且Filer对象与Stream对象捆绑在一起,一方面可以在各种存储媒介中存取任意格式的数据;另一方面,由于充分利用面向对象的动态联编,各种读写方法的使用方法是一致的,因此,方法调用很简单。下面我们着重介绍Reader 对象中与读写数据操作有关的属性和方法的实现。

  1. TReader属性的实现

  在TReader对象的属性实现中我们重点介绍Position的实现。

  Position属性的定义了使用了读写控制,它们分别是GetPositionSetPosition方法。 

TReader = class(TFiler)

private

function GetPosition: Longint;

procedure SetPosition(Value: Longint);

public

property Position: Longint read GetPosition write SetPosition;

end; 

Postition的读写控制方法如下: 

function TReader.GetPosition: Longint;

begin

Result := FStream.Position + FBufPos;

end; 

procedure TReader.SetPosition(Value: Longint);

begin

FStream.Position := Value;

FBufPos := 0;

FBufEnd := 0;

end; 

TReader的父对象TFiler对象中介绍过FBufPosFBufEnd变量。Filer对象内部分配了一个BufSize大小的缓冲区FBufPos就是指在缓冲区中的相对位置,FBufEnd是指在缓冲区中数据结束处的位置(缓冲区中的数据不一定会充满整个缓冲区)

 在GetPosition方法中可以看到Reader对象的Position值和Stream对象的Position值是不同的。Reader对象多了一个FButPos的编移量。

 2. DefinepropertyDefineBinaryproperty方法的实现

这两个方法是虚方法,在TFiler中是抽象方法,在TReaderTWriter对象中才有具体的实现。

  它们在TReader中的实现如下:  

procedure TReader.DefineProperty(const Name: string; ReadData: TReaderProc;

WriteData: TWriterProc; HasData: Boolean);

begin

if CompareText(Name, FPropName) = 0 then

begin

ReadData(Self);

FPropName := '';

end;

end; 

procedure TReader.DefineBinaryProperty(const Name: string;

ReadData, WriteData: TStreamProc; HasData: Boolean);

var

Stream: TMemoryStream;

Count: Longint;

begin

if CompareText(Name, FPropName) = 0 then

begin

if ReadValue <> vaBinary then

begin

Dec(FBufPos);

SkipValue;

FCanHandleExcepts := True;

PropValueError;

end;

Stream := TMemoryStream.Create;

try

Read(Count, SizeOf(Count));

Stream.SetSize(Count);

Read(Stream.Memory^, Count);

FCanHandleExcepts := True;

ReadData(Stream);

finally

Stream.Free;

end;

FPropName := '';

end;

end; 

在两个方法都将Name参数值与当前的属性名比较,如果相同则进行读操作。在DefineBinaryproperty中,创建了一个内存流。先将数据读到内存流中然后调用ReadData读取数据。

  3. FlushBuffer的实现

  FlushBuffer方法用于清除Reader对象的内部缓冲区中的内容,保持Reader对象和流在位置(Position)上的同步,其实现如下: 

procedure TReader.FlushBuffer;

begin

FStream.Position := FStream.Position - (FBufEnd - FBufPos);

FBufPos := 0;

FBufEnd := 0;

end; 

  4. ReadListBeginReadListEndEndOfList方法

  这三个方法都是用于从Reader对象的流中读取一连串的项目,并且这些项目都由WriteListBegin写入的标志标定开始和WriteListEnd写入标志,标定结束,在读循环中用EndOfList进行判断。它们是在Reader对象读取流中数据时经常用于的。它们的实现如下: 

procedure TReader.ReadListBegin;

begin

CheckValue(vaList);

end; 

procedure TReader.ReadListEnd;

begin

CheckValue(vaNull);

end; 

function TReader.EndOfList: Boolean;

begin

Result := ReadValue = vaNull;

Dec(FBufPos);

end; 

  项目表开始标志是VaList,项目表结束标志是VaNullVaListVaNull都是枚举类型TValueType定义的常量。

  它们实现中调用的CheckValueTReader的私有方法,其实现如下: 

procedure TReader.CheckValue(Value: TValueType);

begin

if ReadValue <> Value then

begin

Dec(FBufPos);

SkipValue;

PropValueError;

end;

end; 

  CheckValue方法的功能是检测紧接着要读的值是否是Value指定的类型。如果不是则跳过该项目并触发一个SInvalidPropertyValue错误。

  EndOfList函数只是简单地判断下一字节是否是VaNull将判断结果返回,并将字节移回原来位置。

  5. 简单数据类型读方法的实现

  简单数据类型指的是布尔型、字符型、整型、字符串型、浮点型、集合类型和标识符。将它们放在一起介绍是因为它们的实现方法类似。

  因为它们的实现都用到了ReadValue方法,因此先来介绍ReadValue方法的实现: 

function TReader.ReadValue: TValueType;

begin

Read(Result, SizeOf(Result));

end;  

  该方法调用私有方法Read,从Reader对象流中读一个字节,并移动位置指针。

  ReadValue方法专门从流中读取值的类型的,所有的数据读写方法中在读取数据前都要调用ReadValue方法判断是否是所要读的数据。如果是,则调用Read方法读取数据;否则触发一个异常事件,下面看Integer类型的读方法: 

 
设为首页 | 加入收藏 | 业务办理 | 友情链接 | 论坛版面 | 浙ICP备07502118号 |