首页 / 软件开发 / Delphi / 第二十章-开发Delphi对象式数据管理功能(一)-(2)
第二十章-开发Delphi对象式数据管理功能(一)-(2)2007-05-0720.1.1.2 TStream的实现原理TStream对象是Stream对象的基础类,这是Stream对象的基础。为了能在不同媒介上的存储数据对象,后继的Stream对象主要是在Read和Write方法上做了改进,。因此,了解TStream是掌握Stream对象管理的核心。Borland公司虽然提供了Stream对象的接口说明文档,但对于其实现和应用方法却没有提及,笔者是从Borland Delphi 2.0 Client/Server Suite 提供的源代码和部分例子程序中掌握了流式对象技术。下面就从TStream的属性和方法的实现开始。1. TStream属性的实现前面介绍过,TStream具有Position和Size两个属性,作为抽象数据类型,它抽象了在各种存储媒介中读写数据所需要经常访问的域。那么它们是怎样实现的呢?在自定义部件编写这一章中介绍过部件属性定义中的读写控制。Position和Size也作了读写控制。定义如下:property Position: Longint read GetPosition write SetPosition;property Size: Longint read GetSize;由上可知,Position是可读写属性,而Size是只读的。Position属性的实现就体现在GetPosition和SetPosition。当在程序运行过程中,任何读取Position的值和给Position赋值的操作都会自动触发私有方法GetPosition和SetPosition。两个方法的声明如下:function TStream.GetPosition: Longint;beginResult := Seek(0, 1);end;procedure TStream.SetPosition(Pos: Longint);beginSeek(Pos, 0);end;在设置位置时,Delphi编译机制会自动将Position传为Pos。前面介绍过Seek的使用方法,第一参数是移动偏移量,第二个参数是移动的起点,返回值是移动后的指针位置。Size属性的实现只有读控制,完全屏蔽了写操作。读控制方法GetSize实现如下:function TStream.GetSize: Longint;varPos: Longint;beginPos := Seek(0, 1);Result := Seek(0, 2);Seek(Pos, 0);end;2. TStream方法的实现⑴ CopyFrom方法CopyFrom是Stream对象中很有用的方法,它用于在不同存储媒介中拷贝数据。例如,内存与外部文件之间、内存与数据库字段之间等。它简化了许多内存分配、文件打开和读写等的细节,将所有拷贝操作都统一到Stream对象上。前面曾介绍:CopyFrom方法带Source和Count两个参数并返回长整型。该方法将Count个字节的内容从Source拷贝到当前流中,如果Count值为0则拷贝所有数据。function TStream.CopyFrom(Source: TStream; Count: Longint): Longint;constMaxBufSize = $F000;varBufSize, N: Integer;Buffer: PChar;beginif Count = 0 thenbeginSource.Position := 0;CouNG="ZH-CN">资源文件中的部件时调用,通常程序员不需自己调用。如果读取的不是资源文件ReadResHeader,将触发异常事件。procedure TStream.ReadResHeader;varReadCount: Longint;Header: array[0..79] of Char;beginFillChar(Header, SizeOf(Header), 0);ReadCount := Read(Header, SizeOf(Header) - 1);if (Byte((@Header[0])^) = $FF) and (Word((@Header[1])^) = 10) thenSeek(StrLen(Header + 3) + 10 - ReadCount, 1)elseraise EInvalidImage.CreateRes(SInvalidImage);end;ReadComponentRes在Windows资源文件中读取部件,为了判断是否是资源文件,它首先调用ReadResHeader方法,然后调用ReadComponent方法读取Instance指定的部件。下面是它的实现:function TStream.ReadComponentRes(Instance: TComponent): TComponent;beginReadResHeader;Result := ReadComponent(Instance);end;与ReadComponentRes相应的写方法是WriteComponentRes,Delphi 调用这两个方法读写窗体文件(DFM文件),在后面书中会举用这两个方法读取DFM文件的例子。⑷ WriteComponent和WriteDescendant方法Stream对象的WriteDescendant方法在实现过程中,创建了TWriter对象,然后利用TWriter的WriteDescendant方法将Instance写入流。而WriteComponent方法只是简单地调用WriteDescendant方法将Instance写入流。它们的实现如下:procedure TStream.WriteComponent(Instance: TComponent);beginWriteDescendent(Instance, nil);end;procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);varWriter: TWriter;beginWriter := TWriter.Create(Self, 4096);tryWriter.WriteDescendent(Instance, Ancestor);finallyWriter.Free;end;end;⑸ WriteDescendantRes和WriteComponentRes方法WriteDescendantRes方法用于将部件写入Windows资源文件;而WriteComponentRes 方法只是简单地调用WriteDescendantRes方法,它们的实现如下:procedure TStream.WriteComponentRes(const ResName: string; Instance: TComponent);beginWriteDescendentRes(ResName, Instance, nil);end;procedure TStream.WriteDescendentRes(const ResName: string; Instance,Ancestor: TComponent);varHeaderSize: Integer;Origin, ImageSize: Longint;Header: array[0..79] of Char;beginByte((@Header[0])^) := $FF;Word((@Header[1])^) := 10;HeaderSize := StrLen(StrUpper(StrPLCopy(@Header[3], ResName, 63))) + 10;Word((@Header[HeaderSize - 6])^) := $1030;Longint((@Header[HeaderSize - 4])^) := 0;WriteBuffer(Header, HeaderSize);Origin := Position;WriteDescendent(Instance, Ancestor);ImageSize := Position - Origin;Position := Origin - 4;WriteBuffer(ImageSize, SizeOf(Longint));Position := Origin + ImageSize;end;WriteCompnentRes是与ReadComponentRes相应的对象写方法,这两个方法相互配合可读取Delphi的DFM文件,从而利用Delphi系统的功能。