李道强Delphi中“流”的操作 摘要:“流”是用来实现对大数据量的简捷、快速、方便操作基础。本文分析了在Delphi下,“流” Stream对象的原理,实现方式和基本操作,及TFileStream、TMemoryStream等具体对象的使用方式和应用范围。对使用Delphi开发语言的人员要实现大数据量操作,有一定的借鉴作用。 关键字:面向对象;程序;数据
什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有的操作,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。 在Delphi的早期版本Turbo Pascal 中就曾有流(Stream)、群(Collection)和资源(Resource)等专门用于对象式数据管理的类。在Delphi中,这些功能得到了大大的加强。Delphi将对象式数据管理类归结为Stream对象(Stream)和Filer对象(Filer),并将它们应用于可视部件类库(VCL)的方方面面。它们不仅提供了在内存、外存和Windows资源中管理对象的功能,还提供了在数据库BLOB字段中对象的功能。 在Dephi中提供了一个抽象的数据类型TStream来支持对流式数据的操作。这些数据通常来自文件、数据库、内存对象、OLE对象等,TStream提供了统一、简洁的方法来进行数据的读写。在通常情况下,我们并不需要直接使用TStream类,对流式数据的读写封装在VCL控件的方法中。 图1 Dephi流式对象的VCL封装情况 1、流式对象的实现原理 Stream对象,又称流式对象,是TStream、THandleStream、TFileStream、TMemoryStream、TResourceStream和TBlobStream等的统称。它们分别代表了在各种媒介上存储数据的能力,它们将各种数据类型(包括对象和部件) 在内存、外存和数据库字段中的管理操作抽象为对象方法,并且充分利用了面向对象技术的优点,应用程序可以相当容易地在各种Stream对象中拷贝数据。 (1)TStream对象 实现原理:TStream对象是Stream对象的基础类,这是Stream对象的基础。为了能在不同媒介上的存储数据对象,后继的Stream对象主要是在Read和Write方法上做了改进。 TStream对象是能在各种媒介中存储二进制数据的对象的抽象对象。从TStream 对象继承的对象用于在内存、Windows资源文件、磁盘文件和数据库字段等媒介中存储数据。 TStream中定义了两个属性:Size和Position。它们分别以字节为单位表示的流的大小和当前指针位置。TStream中定义的方法用于在各种流中读、写和相互拷贝二进制数据。因为所有的Stream对象都是从TStream中继承来的,所以在TStream中定义的域和方法都能被Stream对象调用和访问。此外,又由于面向对象技术的动态联编功能,TStream为各种流的应用提供了统一的接口,简化了流的使用;不同Stream对象是抽象了对不同存储媒介的数据上的操作,因此,TStream的需方法为在不同媒介间的数据拷贝提供了最简捷的手段。 (2)THandleStream对象 实现原理:THandleStream在实现上主要是增加了一个属性Handle和覆盖了Create、Read、Write和Seek四个方法。定义了Handle属性,该属性提供了对文件句柄的只读访问,覆盖了构造函数Create,该函数带有Handle 参数,该参数指定与THandleStream对象相关的文件句柄。 (3)TFileStream对象 TFileStream对象是在磁盘文件上存储数据的Stream对象。TFileStream是从THandleStream继承下来的,它和THandleStream一样都是实现文件的存取操作。不同之处在于THandleStream用句柄访问文件,而TFileStream用文件名访问文件。实际上TFileStream是THandleStream上的一层包装,其内核是THandleStream的属性和方法。 TFileStream只覆盖了的构造方法Create和析构方法Destory。在Create方法中带两个参数FileName和Mode。FileName描述要创建或打开的文件名,而Mode描述文件模式如fmCreate、fmOpenRead和fmOpenWrite等。Create方法首先使用FileCreate或FileOpen函数创建或打开名为FileName的文件,再将得到的文件句柄赋给FHandle。TFileStream的文件读写操作都是由从THandleStream继承的。 (4)TMemoryStream对象 TMemoryStream对象是一个管理动态内存中的数据的Stream对象,它是从TCustomMemoryStream中继承下来的,增加和覆盖了一些用于从磁盘文件和其它注台读数据的方法。还提供了写入、消除内存内容的动态内存管理方法。 TCustomMemoryStream是用于内存中数据操作的抽象对象,它为MemoryStream对象的实现提供了框架,框架中的内容还要由具体MemoryStream对象去填充。TMemoryStream对象就是按动态内存管理的需要填充框架中的具体内容。 2、实际应用 (1)利用流制作EXE文件加密器、捆绑、自解压文件及安装程序 EXE文件加密器的原理:建立两个文件,一个用来添加资源到另外一个EXE文件里面,称为添加程序。另外一个被添加的EXE文件称为头文件。该程序的功能是把添加到自己里面的文件读出来。Windows下的EXE文件结构比较复杂,有的程序还有校验和,当发现自己被改变后会认为自己被病毒感染而拒绝执行。所以我们把文件添加到自己的程序里面,这样就不会改变原来的文件结构了。我们先写一个添加函数,该函数的功能是把一个文件当作一个流添加到另外一个文件的尾部。函数如下: function AddtoFile(sFile, tFile: string): Boolean; var t, s: TFileStream; MyFileSize: integer; begin try s := TFileStream.Create(sFile, fmOpenRead or fmShareExclusive); t := TFileStream.Create(tFile, fmOpenWrite or fmShareExclusive); try t.Seek(0, soFromEnd); MyFileSize := s.Size + Sizeof(MyFileSize); t.WriteBuffer(MyFileSize, sizeof(MyFileSize)); finally t.Free; s.Free; end; except Result := False; Exit; end; Result := True; end; 实际使用时,可以使用读出函数,把自己的内容读出来。 function LoadFromFile(sFile, tFile: string): Boolean; var s: TFileStream; t: TMemoryStream; MyFileSize: integer; begin try t := TMemoryStream.Create; s := TFileStream.Create(sFile, fmOpenRead or fmShareDenyNone); try s.Seek(-sizeof(MyFileSize), soFromEnd); s.ReadBuffer(MyFileSize, sizeof(MyFileSize)); s.Seek(-MyFileSize, soFromEnd); t.CopyFrom(s, MyFileSize - sizeof(MyFileSize)); t.SaveToFile(tFile); finally t.Free; s.Free; end; except Result := false; Exit; end; Result := true; end; (2)利用流制作可执行电子贺卡 我们经常看到一些电子贺卡之类的制作软件,可以让你自己选择图片,然后它会生成一个EXE可执行文件给你。打开贺卡时就会一边放音乐一边显示出图片来。 添加图片过程我们可以直接用前面的AddtoFile,而现在要做的是如何把图像读出并显示。我们用前面的LoadFromFile先把图片读出来保存为文件再调入也是可以的,但是还有更简单的方法,就是直接把文件流读出来显示。 现在的图片比较流行的是BMP格式和JPG格式。我们BMP图片为例写出读取函数。 function BmpLoad(Bmp: TBitmap; SourceFile: string): Boolean; var Source: TFileStream; MyFileSize: integer; begin Source := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyNone); try try Source.Seek(-sizeof(MyFileSize), soFromEnd); Source.ReadBuffer(MyFileSize, sizeof(MyFileSize)); Source.Seek(-MyFileSize, soFromEnd); Bmp.LoadFromStream(Source); finally Source.Free; end; except Result := False; Exit; end; Result := True; end; 图片内容读出来了,就可以用其它控件在FORM了显示了。
参考文献: [1] 卢国俊. Delphi 6高级编程[M].北京:电子工业出版社,2002.1 [2] 牛汉民. Delphi 7高级应用开发教程[M].北京:科学出版社,2006.1 [3] 陈省. Delphi 深度探索[M].北京:电子工业出版社,2004.1