汇编 | Java | C# | Delphi | C/C++ |

DELPHI基础教程 第二十章 开发Delphi对象式数据管理功能(一)

第二十章 开发Delphi对象式数据管理功能(一) 内容来自dedecms

  面向对象技术是九十年代的主流技术,各类应用软件如果以面向对象的方法构造并且渗透面向对象的风格将使软件具有更高的品质。在面向对象程序设计中,对象式数据管理占有很重要的地位。在Delphi中,对对象式数据管理的支持方式是其一大特色。 织梦好,好织梦

Delphi是一个面向对象的可视化设计与面向对象的语言相结合的集成开发环境。Delphi的核心是部件。部件是对象的一种。Delphi应用程序完全是由部件来构造的,因此开发高性能的Delphi应用程序必然会涉及对象式数据管理技术。 本文来自织梦

对象式数据管理包括两方面的内容:

织梦好,好织梦

用对象来管理数据

织梦好,好织梦

对各类数据对象(包括对象和部件)的管理 dedecms.com

  dedecms.com

Delphi在这两方面都做的相当出色。在Delphi的早期版本Turbo Pascal 中就曾有流(Stream)、群(Collection)和资源(Resource)等专门用于对象式数据管理的类。在Delphi中,这些功能得到了大大的加强。Delphi将对象式数据管理类归结为Stream对象(Stream)Filer对象(Filer),并将它们应用于可视部件类库(VCL)的方方面面。它们不仅提供了在内存、外存和Windows资源中管理对象的功能,还提供了在数据库BLOB字段中对象的功能。

内容来自dedecms

  在本章中将介绍Stream对象和Filer对象的实现原理、应用方法以及在超媒体系统中的应用。这对于运用Delphi 开发高级应用是很重要的。

织梦好,好织梦

  dedecms.com

20.1 流式对象的实现原理和应用 织梦好,好织梦

  织梦好,好织梦

  Stream对象,又称流式对象,是TStreamTHandleStreamTFileStreamTMemoryStreamTResourceStreamTBlobStream等的统称。它们分别代表了在各种媒介上存储数据的能力,它们将各种数据类型(包括对象和部件) 在内存、外存和数据库字段中的管理操作抽象为对象方法,并且充分利用了面向对象技术的优点,应用程序可以相当容易地在各种Stream对象中拷贝数据。

内容来自dedecms

  下面介绍各种对象的数据和方法及使用方法。 织梦好,好织梦

  本文来自织梦

20.1.1 TStream对象 织梦好,好织梦

 

copyright dedecms

  TStream对象是能在各种媒介中存储二进制数据的对象的抽象对象。从TStream 对象继承的对象用于在内存、Windows资源文件、磁盘文件和数据库字段等媒介中存储数据。 织梦好,好织梦

  TStream中定义了两个属性:SizePosition。它们分别以字节为单位表示的流的大小和当前指针位置。TStream中定义的方法用于在各种流中读、写和相互拷贝二进制数据。因为所有的Stream对象都是从TStream中继承来的,所以在TStream中定义的域和方法都能被Stream对象调用和访问。此外,又由于面向对象技术的动态联编功能,TStream为各种流的应用提供了统一的接口,简化了流的使用;不同Stream对象是抽象了对不同存储媒介的数据上的操作,因此,TStream的需方法为在不同媒介间的数据拷贝提供了最简捷的手段。

织梦内容管理系统

  内容来自dedecms

20.1.1.1 TStream的属性和方法

copyright dedecms

 

copyright dedecms

  1. Position属性  织梦内容管理系统

声明:property Position: Longint;

copyright dedecms

  Position属性指明流中读写的当前偏移量。

织梦好,好织梦

  2. Size属性

内容来自dedecms

  声明:property Size: Longint;

织梦内容管理系统

Size属性指明了以字节为单位的流的的大小,它是只读的。 内容来自dedecms

  3. CopyFrom方法

织梦内容管理系统

  声明:function CopyFrom(Source: TStream; Count: Longint): Longint; 织梦好,好织梦

CopyFromSource所指定的流中拷贝Count个字节到当前流中, 并将指针从当前位置移动Count个字节数,函数返回值是实际拷贝的字节数。 dedecms.com

  4. Read方法 dedecms.com

  声明:function Read(var Buffer; Count: Longint): Longint; virtual; abstract; dedecms.com

Read方法从当前流中的当前位置起将Count个字节的内容复制到Buffer中,并把当前指针向后移动Count个字节数,函数返回值是实际读的字节数。如果返回值小于Count,这意味着读操作在读满所需字节数前指针已经到达了流的尾部。

织梦好,好织梦

  Read方法是抽象方法。每个后继Stream对象都要根据自己特有的有关特定存储媒介的读操作覆盖该方法。而且流的所有其它的读数据的方法(如:ReadBufferReadComponent等)在完成实际的读操作时都调用了Read方法。面向对象的动态联编的优点就体现在这儿。因为后继Stream对象只需覆盖Read方法,而其它读操作(ReadBufferReadComponent)都不需要重新定义,而且TStream还提供了统一的接口。

copyright dedecms

  5. ReadBuffer方法 织梦内容管理系统

  声明:procedure ReadBuffer(var Buffer; Count: Longint); 内容来自dedecms

  ReadBuffer方法从流中将Count个字节复制到Buffer 中, 并将流的当前指针向后移动Count个字节。如读操作超过流的尾部,ReadBuffer方法引起EReadError异常事件。

dedecms.com

  6. ReadComponent方法

织梦内容管理系统

  声明:function ReadComponent(Instance: TComponent): TComponent;

copyright dedecms

ReadComponent方法从当前流中读取由Instance所指定的部件,函数返回所读的部件。ReadComponent在读Instance及其拥有的所有对象时创建了一个Reader对象并调用它的ReadRootComponent方法。 织梦内容管理系统

  如果InstancenilReadComponent的方法基于流中描述的部件类型信息创建部件,并返回新创建的部件。

copyright dedecms

  7. ReadComponentRes方法

织梦内容管理系统

  声明:function ReadComponentRes(Instance: TComponent): TComponent; 织梦内容管理系统

ReadComponentRes方法从流中读取Instance指定的部件,但是流的当前位置必须是由WriteComponentRes方法所写入的部件的位置。

dedecms.com

  ReadComponentRes 首先调用ReadResHeader方法从流中读取资源头,然后调用ReadComponent方法读取Instance。如果流的当前位置不包含一个资源头。ReadResHeader将引发一个EInvalidImage异常事件。在Classes库单元中也包含一个名为ReadComponentRes的函数,该函数执行相同的操作,只不过它基于应用程序包含的资源建立自己的流。

本文来自织梦

  8. ReadResHeader方法

本文来自织梦

  声明:procedure ReadResHeader; 织梦内容管理系统

ReadResHeader方法从流的当前位置读取Windows资源文件头,并将流的当前位置指针移到该文件头的尾部。如果流不包含一个有效的资源文件头,ReadResHeader将引发一个EInvalidImage异常事件。

织梦好,好织梦

  流的ReadComponentRes方法在从资源文件中读取部件之前,会自动调用ReadResHeader方法,因此,通常程序员通常不需要自己调用它。 织梦内容管理系统

  9. Seek方法

织梦好,好织梦

  声明:function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract; 内容来自dedecms

Seek方法将流的当前指针移动Offset个字节,字节移动的起点由Origin指定。如果Offset是负数,Seek方法将从所描述的起点往流的头部移动。下表中列出了Origin的不同取值和它们的含义:

织梦内容管理系统

 

织梦好,好织梦

20.1 函数Seek的参数的取值 内容来自dedecms

 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

dedecms.com

  常量       值      Seek的起点 Offset的取值

copyright dedecms

───────────────────────────────── dedecms.com

 SoFromBeginning 0  流的开头 织梦内容管理系统

 SoFromCurrent 1 流的当前位置 正数或负数 本文来自织梦

 SoFromEnd 2 流的结尾 copyright dedecms

 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

织梦好,好织梦

 

织梦好,好织梦

  10. Write方法 本文来自织梦

  在Delphi对象式管理的对象中有两类对象的方法都有称为Write的:Stream对象和Filer对象。Stream对象的Write方法将数据写进流中。Filer对象通过相关的流传递数据,在后文中会介绍这类方法。 本文来自织梦

  Stream对象的Write方法声明如下: 织梦内容管理系统

 

copyright dedecms

function Write(const Buffer; Count: Longint): Longint; virtual; abstract;

织梦好,好织梦

 

织梦好,好织梦

Write方法将Buffer中的Count个字节写入流中,并将当前位置指针向流的尾部移动Count个字节,函数返回写入的字节数。

本文来自织梦

  TStreamWrite方法是抽象的,每个继承的Stream对象都要通过覆盖该方法来提供向特定存储媒介(内存、磁盘文件等)写数据的特定方法。流的其它所有写数据的方法(WriteBufferWriteComponent)都调用Write担当实际的写操作。

内容来自dedecms

  11. WriteBuffer方法

copyright dedecms

  声明:procedure WriteBuffer(const Buffer; Count: Longint); copyright dedecms

  WriteBuffer的功能与Write相似。WriteBuffer方法调用Write来执行实际的写操作,如果流没能写所有字节,WriteBuffer会触发一个EWriteError异常事件。

织梦内容管理系统

  12. WriteComponent方法 copyright dedecms

  在Stream对象和Filer对象都有被称为WriteComponent的方法。Stream对象的WriteComponent方法将Instance所指定的部件和它所包含的所有部件都写入流中;Writer对象的WriteComponent将指定部件的属性值写入Writer对象的流中。 织梦好,好织梦

  Stream对象的WriteComponent方法声明是这样的: 内容来自dedecms

procedure WriteComponent(Instance: Tcomponent);

dedecms.com

 

本文来自织梦

  WriteComponent创建一个Writer对象,并调用WriterWriteRootComponent方法将Instance及其拥有的对象写入流。

dedecms.com

  13. WriteComponentRes方法 织梦内容管理系统

  声明:WriteComponentRes(const ResName: String; Instance: TComponent);

本文来自织梦

  WriteComponentRes方法首先往流中写入标准Windows 资源文件头,然后将Instance指定的部件写入流中。要读由WriteComponentRes写入的部件,必须调用ReadComponentRes方法。 内容来自dedecms

  WriteComponentRes使用ResName传入的字符串作为资源文件头的资源名,然后调用WriteComponent方法将Instance和它拥有的部件写入流。 dedecms.com

  14. WriteDescendant方法

本文来自织梦

  声明:procedure WriteDescendant(Instance Ancestor: TComponent); copyright dedecms

  Stream对象的WriteDescendant方法创建一个Writer对象,然后调入该对象的WriteDescendant方法将Instance部件写入流中。Instance可以是从Ancestor部件继承的窗体,也可以是在从祖先窗体中继承的窗体中相应于祖先窗体中Ancestor部件的部件。 copyright dedecms

  15. WriteDescendantRes方法 织梦内容管理系统

  声明:procedure WriteDescendantRes(const ResName: String;

织梦内容管理系统

Instance, Ancestor: TComponent);

copyright dedecms

  WriteDescendantRes方法将Windows资源文件头写入流,并使用ResName作用资源名,然后调用WriteDescendant方法,将Instance写入流。

dedecms.com

 

织梦好,好织梦

20.1.1.2 TStream的实现原理 织梦内容管理系统

  本文来自织梦

  TStream对象是Stream对象的基础类,这是Stream对象的基础。为了能在不同媒介上的存储数据对象,后继的Stream对象主要是在ReadWrite方法上做了改进,。因此,了解TStream是掌握Stream对象管理的核心。Borland公司虽然提供了Stream对象的接口说明文档,但对于其实现和应用方法却没有提及,笔者是从Borland Delphi 2.0 Client/Server Suite 提供的源代码和部分例子程序中掌握了流式对象技术。

内容来自dedecms

  下面就从TStream的属性和方法的实现开始。

dedecms.com

  1. TStream属性的实现

内容来自dedecms

  前面介绍过,TStream具有PositionSize两个属性,作为抽象数据类型,它抽象了在各种存储媒介中读写数据所需要经常访问的域。那么它们是怎样实现的呢?

内容来自dedecms

  在自定义部件编写这一章中介绍过部件属性定义中的读写控制。PositionSize也作了读写控制。定义如下: copyright dedecms

 

本文来自织梦

property Position: Longint read GetPosition write SetPosition;

内容来自dedecms

property Size: Longint read GetSize; copyright dedecms

  dedecms.com

  由上可知,Position是可读写属性,而Size是只读的。

织梦内容管理系统

  Position属性的实现就体现在GetPositionSetPosition。当在程序运行过程中,任何读取Position的值和给Position赋值的操作都会自动触发私有方法GetPositionSetPosition。两个方法的声明如下:

本文来自织梦

 

copyright dedecms

function TStream.GetPosition: Longint; 织梦内容管理系统

begin copyright dedecms

Result := Seek(0, 1); copyright dedecms

end; 内容来自dedecms

 

copyright dedecms

procedure TStream.SetPosition(Pos: Longint);

dedecms.com

begin dedecms.com

Seek(Pos, 0);

织梦内容管理系统

end;

内容来自dedecms

 

织梦内容管理系统

在设置位置时,Delphi编译机制会自动将Position传为Pos copyright dedecms

  前面介绍过Seek的使用方法,第一参数是移动偏移量,第二个参数是移动的起点,返回值是移动后的指针位置。

dedecms.com

  Size属性的实现只有读控制,完全屏蔽了写操作。读控制方法GetSize实现如下:

本文来自织梦

 

dedecms.com

function TStream.GetSize: Longint;

dedecms.com

var

内容来自dedecms

Pos: Longint; copyright dedecms

begin 织梦内容管理系统

Pos := Seek(0, 1); 内容来自dedecms

Result := Seek(0, 2); 织梦好,好织梦

Seek(Pos, 0); 内容来自dedecms

end;

本文来自织梦

  dedecms.com

2. TStream方法的实现

本文来自织梦

  ⑴ CopyFrom方法 内容来自dedecms

  CopyFromStream对象中很有用的方法,它用于在不同存储媒介中拷贝数据。例如,内存与外部文件之间、内存与数据库字段之间等。它简化了许多内存分配、文件打开和读写等的细节,将所有拷贝操作都统一到Stream对象上。 本文来自织梦

  前面曾介绍:CopyFrom方法带SourceCount两个参数并返回长整型。该方法将Count个字节的内容从Source拷贝到当前流中,如果Count值为0则拷贝所有数据。 copyright dedecms

  织梦内容管理系统

function TStream.CopyFrom(Source: TStream; Count: Longint): Longint;

织梦好,好织梦

const dedecms.com

MaxBufSize = $F000;

dedecms.com

var copyright dedecms

BufSize, N: Integer; copyright dedecms

Buffer: PChar;

copyright dedecms

begin

copyright dedecms

if Count = 0 then dedecms.com

begin 内容来自dedecms

Source.Position := 0;

dedecms.com

CouNG="ZH-CN">资源文件中的部件时调用,通常程序员不需自己调用。如果读取的不是资源文件ReadResHeader,将触发异常事件。

织梦内容管理系统

 

本文来自织梦

procedure TStream.ReadResHeader;

内容来自dedecms

var

织梦好,好织梦

ReadCount: Longint;

织梦好,好织梦

Header: array[0..79] of Char;

dedecms.com

begin

copyright dedecms

FillChar(Header, SizeOf(Header), 0); 内容来自dedecms

ReadCount := Read(Header, SizeOf(Header) - 1);

本文来自织梦

if (Byte((@Header[0])^) = $FF) and (Word((@Header[1])^) = 10) then

copyright dedecms

Seek(StrLen(Header + 3) + 10 - ReadCount, 1) 本文来自织梦

else

copyright dedecms

raise EInvalidImage.CreateRes(SInvalidImage); 内容来自dedecms

end; 织梦好,好织梦

  织梦内容管理系统

  ReadComponentResWindows资源文件中读取部件,为了判断是否是资源文件,它首先调用ReadResHeader方法,然后调用ReadComponent方法读取Instance指定的部件。下面是它的实现: 内容来自dedecms

  本文来自织梦

function TStream.ReadComponentRes(Instance: TComponent): TComponent; 内容来自dedecms

begin

copyright dedecms

ReadResHeader; dedecms.com

Result := ReadComponent(Instance); 本文来自织梦

end;

内容来自dedecms

 

织梦内容管理系统

 与ReadComponentRes相应的写方法是WriteComponentResDelphi 调用这两个方法读写窗体文件(DFM文件),在后面书中会举用这两个方法读取DFM文件的例子。

织梦内容管理系统

  ⑷ WriteComponentWriteDescendant方法 织梦内容管理系统

  Stream对象的WriteDescendant方法在实现过程中,创建了TWriter对象,然后利用TWriterWriteDescendant方法将Instance写入流。而WriteComponent方法只是简单地调用WriteDescendant方法将Instance写入流。它们的实现如下:

copyright dedecms

   内容来自dedecms

procedure TStream.WriteComponent(Instance: TComponent);

本文来自织梦

begin

织梦好,好织梦

WriteDescendent(Instance, nil);

织梦内容管理系统

end; copyright dedecms

 

织梦好,好织梦

procedure TStream.WriteDescendent(Instance, Ancestor: TComponent); 织梦好,好织梦

var

织梦好,好织梦

Writer: TWriter; 织梦内容管理系统

begin 本文来自织梦

Writer := TWriter.Create(Self, 4096);

织梦内容管理系统

try dedecms.com

Writer.WriteDescendent(Instance, Ancestor); 本文来自织梦

finally 内容来自dedecms

Writer.Free; 内容来自dedecms

end; 织梦好,好织梦

end; 织梦好,好织梦

  dedecms.com

  ⑸ WriteDescendantResWriteComponentRes方法

copyright dedecms

  WriteDescendantRes方法用于将部件写入Windows资源文件;而WriteComponentRes 方法只是简单地调用WriteDescendantRes方法,它们的实现如下:

织梦内容管理系统

 

本文来自织梦

procedure TStream.WriteComponentRes(const ResName: string; Instance:

dedecms.com

TComponent);

内容来自dedecms

begin

本文来自织梦

WriteDescendentRes(ResName, Instance, nil);

本文来自织梦

end;

织梦好,好织梦

  织梦好,好织梦

procedure TStream.WriteDescendentRes(const ResName: string; Instance, dedecms.com

Ancestor: TComponent);

本文来自织梦

var 织梦好,好织梦

HeaderSize: Integer; 织梦内容管理系统

Origin, ImageSize: Longint; dedecms.com

Header: array[0..79] of Char; copyright dedecms

begin

织梦好,好织梦

Byte((@Header[0])^) := $FF; copyright dedecms

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;

内容来自dedecms

WriteDescendent(Instance, Ancestor);

织梦内容管理系统

ImageSize := Position - Origin;

dedecms.com

Position := Origin - 4;

dedecms.com

WriteBuffer(ImageSize, SizeOf(Longint));

copyright dedecms

Position := Origin + ImageSize; 内容来自dedecms

end; copyright dedecms

 

织梦内容管理系统

  WriteCompnentRes是与ReadComponentRes相应的对象写方法,这两个方法相互配合可读取DelphiDFM文件,从而利用Delphi系统的功能。 dedecms.com

  dedecms.com

20.1.2 THandleStream对象 本文来自织梦

  本文来自织梦

  THandleStream对象的行为特别象FileStream对象,所不同的是它通过已创建的文件句柄而不是文件名来存储流中的数据。

织梦好,好织梦

  THandleStream对象定义了Handle属性,该属性提供了对文件句柄的只读访问,并且Handle属性可以作为DelphiRTL文件管理函数的参数,利用文件类函数来读写数据。THandleStream覆盖了构造函数Create,该函数带有Handle 参数,该参数指定与THandleStream对象相关的文件句柄。 copyright dedecms

 

织梦好,好织梦

20.1.2.1 THandleStream的属性的方法:

dedecms.com

  织梦好,好织梦

  1. Handle属性

织梦好,好织梦

  声明:property Handle: Integer; 本文来自织梦

Handle属性提供了对文件句柄的只读访问,该句柄由THandleStream的构造方法Create传入。因此除了用THandleStream提供的方法外,也可以用文件管理函数对句柄进行操作。实际上,THandleStream的方法在实现上也是运用文件管理函数进行实际的读写操作。 dedecms.com

  2. Create方法 本文来自织梦

  声明:constructor Create(AHandle: Integer); 内容来自dedecms

  Create方法使用传入的Handle参数创建一个与特定文件句柄相联的THandleStream对象,并且将AHandle赋给流的Handle属性。 织梦内容管理系统

 

dedecms.com

  3. ReadWriteSeek方法

内容来自dedecms

  这三个方法是TStream的虚方法,只是在THandleStream 中覆盖了这三个方法,以实现特定媒介──文件的数据存取。后面会详细介绍这三个方法的实现。

织梦好,好织梦

 

织梦内容管理系统

20.1.2.2 THandleStream的实现原理 dedecms.com

 

内容来自dedecms

  THandleStream是从TStream继承来的,因此可以共用TStream中的属性和大多数方法。THandleStream在实现上主要是增加了一个属性Handle和覆盖了CreateReadWriteSeek四个方法。

织梦好,好织梦

  1. 属性的实现 织梦内容管理系统

  Handle属性的实现正如Delphi大多数属性的实现那样,先在对象定义的private部分声明一个存放数据的变量FHandle,然后在定义的public部分声明属性Handle,其中属性定义的读写控制部分加上只读控制,读控制只是直接读取FHandle变量的值,其实现如下: 织梦好,好织梦

 

本文来自织梦

THandleStream = class(TStream) 本文来自织梦

private 内容来自dedecms

FHandle: Integer;

本文来自织梦

public 织梦内容管理系统

dedecms.com

property Handle: Integer read FHandle; 织梦内容管理系统

end; 内容来自dedecms

 

织梦好,好织梦

2. 方法的实现 copyright dedecms

  THandleStreamCreate方法,以AHandle作为参数,在方法里面只是简单的将AHandle的值赋给FHandle,其实现如下:

织梦好,好织梦

 

copyright dedecms

constructor THandleStream.Create(AHandle: Integer); 本文来自织梦

begin copyright dedecms

FHandle := AHandle; dedecms.com

end; 内容来自dedecms

 

dedecms.com

  为实现针对文件的数据对象存储,THandleStreamReadWriteSeek方法覆盖了TStream中的相应方法。它们的实现都调用了Windows的文件管理函数。

copyright dedecms

  Read方法调用FileRead函数实现文件读操作,其实现如下:

织梦好,好织梦

  copyright dedecms

function THandleStream.Read(var Buffer; Count: Longint): Longint;

dedecms.com

begin

dedecms.com

Result := FileRead(FHandle, Buffer, Count); dedecms.com

if Result = -1 then Result := 0; 内容来自dedecms

end;

织梦内容管理系统

 

织梦内容管理系统

  Write方法调用FileWrite函数实现文件写操作,其实现如下: 织梦好,好织梦

 

copyright dedecms

function THandleStream.Write(const Buffer; Count: Longint): Longint; 织梦好,好织梦

begin

本文来自织梦

Result := FileWrite(FHandle, Buffer, Count); 内容来自dedecms

if Result = -1 then Result := 0; 织梦内容管理系统

end;

本文来自织梦

  本文来自织梦

  Seek方法调用FileSeek函数实现文件指针的移动,其实现如下: dedecms.com

 

本文来自织梦

function THandleStream.Seek(Offset: Longint; Origin: Word): Longint; 织梦好,好织梦

begin 织梦内容管理系统

Result := FileSeek(FHandle, Offset, Origin); 内容来自dedecms

end; 织梦好,好织梦

 

织梦内容管理系统

20.1.3 TFileStream对象 本文来自织梦

  织梦好,好织梦

  TFileStream对象是在磁盘文件上存储数据的Stream对象。TFileStream是从THandleStream继承下来的,它和THandleStream一样都是实现文件的存取操作。不同之处在于THandleStream用句柄访问文件,而TFileStream用文件名访问文件。实际上TFileStreamTHandleStream上的一层包装,其内核是THandleStream的属性和方法。 内容来自dedecms

  TFileStream中没有增加新的属性和方法。它只是覆盖了的构造方法Create和析构方法Destory。在Create方法中带两个参数FileNameModeFileName描述要创建或打开的文件名,而Mode描述文件模式如fmCreatefmOpenReadfmOpenWrite等。Create方法首先使用FileCreateFileOpen函数创建或打开名为FileName的文件,再将得到的文件句柄赋给FHandleTFileStream的文件读写操作都是由从THandleStream继承的Read 织梦内容管理系统

内容来自dedecms

var 织梦好,好织梦

Stream: TStream;

本文来自织梦

begin dedecms.com

Stream := TFileStream.Create(FileName, fmCreate); 本文来自织梦

try

dedecms.com

SaveToStream(Stream); 本文来自织梦

finally

织梦好,好织梦

Stream.Free; 织梦内容管理系统

end; 织梦好,好织梦

end;

dedecms.com

  本文来自织梦

  在Delphi 的许多对象的SaveToStream SaveToFileLoadFromStreamLoadFromFile方法的实现都有类似的嵌套结构。

内容来自dedecms

  织梦内容管理系统

20.1.5 TMemoryStream对象 内容来自dedecms

 

织梦内容管理系统

  TMemoryStream对象是一个管理动态内存中的数据的Stream对象,它是从TCustomMemoryStream中继承下来的,除了从TCustomMemoryStream中继承的属性和方法外,它还增加和覆盖了一些用于从磁盘文件和其它注台读数据的方法。它还提供了写入、消除内存内容的动态内存管理方法。下面介绍它的这些属性和方法。 dedecms.com

  本文来自织梦

20.1.5.1 TMemoryStream的属性和方法 织梦内容管理系统

  织梦内容管理系统

  1. Capacity属性

本文来自织梦

  声明:property Copacity: Longint; 织梦内容管理系统

Capacity属性决定了分配给内存流的内存池的大小。这与Size属性有些不同。Size属性是描述流中数据的大小。在程序中可以将Capacity 的值设置的比数据所需最大内存大一些,这样可以避免频繁地重新分配。 本文来自织梦

  2. Realloc方法

copyright dedecms

  声明:function Realloc(var NewCapacity: Longint): Pointer; virtual; 内容来自dedecms

Realloc方法,以8K为单位分配动态内存,内存的大小由NewCapacity指定,函数返回指向所分配内存的指针。

copyright dedecms

  3. SetSize方法 内容来自dedecms

  SetSize方法消除内存流中包含的数据,并将内存流中内存池的大小设为Size字节。如果Size为零,是SetSize方法将释放已有的内存池,并将Memory属性置为nil;否则,SetSize方法将内存池大小调整为Size 织梦好,好织梦

4. Clear方法

dedecms.com

  声明:procedure Clear;

织梦内容管理系统

Clear方法释放内存中的内存池,并将Memory属性置为nil。在调用Clear方法后,SizePosition属性都为0 内容来自dedecms

  5. LoadFromStream方法

dedecms.com

  声明:procedure LoadFromStream(Stream: TStream);

dedecms.com

LoadFromStream方法将Stream指定的流中的全部内容复制到MemoryStream中,复制过程将取代已有内容,使MemoryStream成为Stream的一份拷贝。

本文来自织梦

  6. LoadFromFile方法 copyright dedecms

  声明:procedure LoadFromFile(count FileName: String);

内容来自dedecms

LoadFromFile方法将FileName指定文件的所有内容复制到MemoryStream中,并取代已有内容。调用LoadFromFile方法后,MemoryStream将成为文件内容在内存中的完整拷贝。 本文来自织梦

 

dedecms.com

20.1.5.2 TMemoryStream对象的实现原理 本文来自织梦

  织梦好,好织梦

  TMemoryStreamTCustomMemoryStream对象直接继承,因此可以享用TCustomMemoryStream的属性和方法。前面讲过,TCustomMemoryStream是用于内存中数据操作的抽象对象,它为MemoryStream对象的实现提供了框架,框架中的内容还要由具体MemoryStream对象去填充。TMemoryStream对象就是按动态内存管理的需要填充框架中的具体内容。下面介绍TMemoryStream对象的实现。 copyright dedecms

  1. TMemoryStream属性的实现

织梦好,好织梦

  TMemoryStream在其protected部分增加了一个Capacity属性,该属性决定了MemoryStream所占动态内存的大小。TMemoryStream首先在private部分声明了FCapacity变量作为存储Capacity属性值的数据域,然后在protected部分声明了该属性。在属性声明的读控制部分简单读取FCapacity的值,在写控制处调用了方法SetCapacity。该方法除了给FCapacity赋值外还执行了修改Capacity属性所必需操作如状态改变等。

本文来自织梦

  下面是属性的实现:

dedecms.com

 

织梦好,好织梦

TMemoryStream = class(TCustomMemoryStream) 织梦内容管理系统

private copyright dedecms

FCapacity: Longint;

dedecms.com

procedure SetCapacity(NewCapacity: Longint);

织梦内容管理系统

protected 内容来自dedecms

本文来自织梦

property Capacity: Longint read FCapacity write SetCapacity; 织梦好,好织梦

public

织梦内容管理系统

织梦内容管理系统

end; copyright dedecms

  dedecms.com

  写控制方法SetCapacity的实现是这样的:

本文来自织梦

 

copyright dedecms

procedure TMemoryStream.SetCapacity(NewCapacity: Longint);

本文来自织梦

begin

本文来自织梦

SetPointer(Realloc(NewCapacity), FSize); dedecms.com

FCapacity := NewCapacity; copyright dedecms

end;

织梦好,好织梦

  内容来自dedecms

  在SetCapacity 方法先是调用Realloc重新分配内存,然后用NewCapacity的值给FCapacity赋值。Realloc方法进行某些对象状态的改变。

内容来自dedecms

  2. TMemoryStream对象方法的实现 织梦好,好织梦

  ⑴ Realloc方法 内容来自dedecms

  Realloc方法是TMemoryStream动态内存分配的核心,它的SetSizeSetCapacity等方法最终都是调用Realloc进行内存的分配和初始化工作的。它的实现如下:

dedecms.com

  dedecms.com

const copyright dedecms

MemoryDelta = $2000;

织梦好,好织梦

  内容来自dedecms

function TMemoryStream.Realloc(var NewCapacity: Longint): Pointer; 织梦内容管理系统

begin 内容来自dedecms

if NewCapacity > 0 then

织梦好,好织梦

NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1); dedecms.com

Result := Memory; copyright dedecms

if NewCapacity <> FCapacity then

织梦内容管理系统

begin

dedecms.com

if NewCapacity = 0 then

织梦好,好织梦

begin

dedecms.com

GlobalFreePtr(Memory); 本文来自织梦

Result := nil;

本文来自织梦

end else copyright dedecms

begin

织梦内容管理系统

if Capacity = 0 then dedecms.com

Result := GlobalAllocPtr(HeapAllocFlags, NewCapacity) 本文来自织梦

else

内容来自dedecms

Result := GlobalReallocPtr(Memory, NewCapacity, HeapAllocFlags); 本文来自织梦

if Result = nil then raise EStreamError.CreateRes(SMemoryStreamError);

织梦内容管理系统

end;

copyright dedecms

end;

织梦好,好织梦

end; 本文来自织梦

 

dedecms.com

  Realloc方法是以8K为单位分配动态内存的,方法中的第一句if语句就是执行该操作。如果传入的NewCapacity参数值为0,则释放流中的内存。Realloc方法用GLobal FreePtr函数释放内存,用GlobalAllocPtr分配内存,用GlobalReallocPtr进行内存的重分配。如果原来的Capacity属性值为0,则调用Globa|AllocPtr否则调用GlobalReallocPtr。最后如果Resultnil则触发内存流错的异常事件,否则返回指向分配的内存的指针。

本文来自织梦

  ⑵ Write方法 内容来自dedecms

  Write方法从内存流内部缓冲池的当前位置开始写入二进制数据。其实现如下: 内容来自dedecms

 

本文来自织梦

function TMemoryStream.Write(const Buffer; Count: Longint): Longint; dedecms.com

var 织梦好,好织梦

Pos: Longint;

内容来自dedecms

begin

本文来自织梦

if (FPosition >= 0) and (Count >= 0) then copyright dedecms

begin 本文来自织梦

Pos := FPosition + Count; 织梦内容管理系统

if Pos > 0 then 织梦好,好织梦

begin

织梦好,好织梦

if Pos > FSize then

织梦好,好织梦

begin 织梦内容管理系统

if Pos > FCapacity then 本文来自织梦

SetCapacity(Pos);

dedecms.com

FSize := Pos;

织梦好,好织梦

end; copyright dedecms

System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);

本文来自织梦

FPosition := Pos;

织梦好,好织梦

Result := Count; dedecms.com

Exit; copyright dedecms

end; dedecms.com

end; 织梦好,好织梦

Result := 0;

织梦好,好织梦

end;

本文来自织梦

 

织梦内容管理系统

  Buffer中存储要写入流的二进制数据,如果要写入的数据的字节超出了流的内存池的大小,则调用SetCapacity方法再分配内存,然后用内存复制函数将Buffer中的数据复制到FMemory中。接着移动位置指针,并返回写入数据的字节数。分析这段程序可以知道,FCapacity的值和FSize的值是不同的。

内容来自dedecms

  ⑶ Clear方法 织梦好,好织梦

  Clear方法消除内存流中的数据,将Memory属性置为nil,并将FSizeFPosition 的值设为0。其实现如下: 内容来自dedecms

 

dedecms.com

procedure TMemoryStream.Clear; 织梦好,好织梦

begin dedecms.com

SetCapacity(0);

copyright dedecms

FSize := 0; 织梦内容管理系统

FPosition := 0; 织梦好,好织梦

end; 织梦好,好织梦

  内容来自dedecms

  ⑷ LoadFromStreamLoadFromFile方法 织梦内容管理系统

  LoadFromStream方法首先根据传入的StreamSize属性值重新分配动态内存,然后调用StreamReadBuffer方法往FMemory中复制数据,结果Stream的全部内容在内存中有了一份完整拷贝。其实现如下:

织梦好,好织梦

 

本文来自织梦

procedure TMemoryStream.LoadFromStream(Stream: TStream); 织梦内容管理系统

var dedecms.com

Count: Longint;

内容来自dedecms

begin copyright dedecms

Stream.Position := 0;

内容来自dedecms

Count := Stream.Size; copyright dedecms

SetSize(Count); 织梦好,好织梦

if Count <> 0 then Stream.ReadBuffer(FMemory^, Count); 本文来自织梦

end;  织梦内容管理系统

  LoadFromFileLoadFromStream是一对方法。LoadFromFile首先创建了一个TFileStream对象,然后调用LoadFromStream方法,将FileStream文件流中的数据写入MemoryStream中。 织梦内容管理系统

 

织梦好,好织梦

织梦好,好织梦

精彩推荐
热点内容
最近更新