DELPHI Stream对象

  Stream 对象,又称流式对象,是 TStream THandleStream TFileStream TMemoryStream TResourceStream TBlobStream 等的统称。它们分别代表了在各种媒介上存储数据的能力,它们将各种数据类型 ( 包括对象和部件

在内存、外存和数据库字段中的管理操作抽象为对象方法,并且充分利用了面向对象技术的优点,应用程序可以相当容易地在各种 Stream 对象中拷贝数据。

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

 

TStream 对象

 

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

  Stream 中定义了两个属性: Size Position 。它们分别以字节为单位表示的流的大小和当前指针位置。 TStream 中定义的方法用于在各种流中读、写和相互拷贝二进制数据。因为所有的 Stream 对象都是从 TStream 中继承来的,所以在 TStream 中定义的域和方法都能被 Stream 对象调用和访

问。此外,又由于面向对象技术的动态联编功能, TStream 为各种流的应用提供了统一的接口,简化了流的使用;不同 Stream 对象是抽象了对不同存储媒介的数据上的操作,因此, TStream 的需方法为在不同媒介间的数据拷贝提供了最简捷的手段。

 

TStream 的属性和方法

 

   1. Position 属性 

     声明: property Position: Longint; 

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

   2. Size 属性

  声明: property Size: Longint; 

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

   3. CopyFrom 方法

  声明: function CopyFrom(Source: TStream; Count: Longint): Longint; 

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

   4. Read 方法

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

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

   Read 方法是抽象方法。每个后继 Stream 对象都要根据自己特有的有关特定存储媒介的读操作覆盖该方法。而且流的所有其它的读数据的方法(如: ReadBuffer ReadComponent 等)在完成实际的读操作时都调用了 Read 方法。面向对象的动态联编的优点就体现在这儿。因为后继 Stream

象只需覆盖 Read 方法,而其它读操作 ( ReadBuffer ReadComponent ) 都不需要重新定义,而且 TStream 还提供了统一的接口。

   5. ReadBuffer 方法

  声明: procedure ReadBuffer(var Buffer; Count: Longint); 

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

   6. ReadComponent 方法

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

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

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

   7. ReadComponentRes 方法

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

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

   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; 

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

 

                           函数 Seek 的参数的取值

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

  常量       值       Seek 的起点          Offset 的取值

   ─────────────────────────────────

  SoFromBeginning     0            流的开头              

  SoFromCurrent       1              流的当前位置         正数或负数   

  SoFromEnd          2              流的结尾              

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

                   

     10. Write 方法

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

   Stream 对象的 Write 方法声明如下:

 

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

 

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

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

   11. WriteBuffer 方法

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

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

   12. WriteComponent 方法

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

   Stream 对象的 WriteComponent 方法声明是这样的:

        procedure WriteComponent(Instance: Tcomponent); 

 

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

   13. WriteComponentRes 方法

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

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

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

   14. WriteDescendant 方法

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

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

   15. WriteDescendantRes 方法

  声明: procedure WriteDescendantRes(const ResName: String;

                                         Instance, Ancestor: TComponent);

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

 

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;

     begin

       Result := Seek(0, 1);

     end;

 

     procedure TStream.SetPosition(Pos: Longint);

     begin

       Seek(Pos, 0);

     end;

 

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

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

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

 

     function TStream.GetSize: Longint;

     var

       Pos: Longint;

     begin

       Pos := 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;

      const

       MaxBufSize = $F000;

     var

       BufSize, N: Integer;

       Buffer: PChar;

     begin

       if Count = 0 then

       begin

         Source.Position := 0;

         Count := Source.Size;

       end;

       Result := Count;

        if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count;

       GetMem(Buffer, BufSize);

       try

         while Count <> 0 do

         begin

           if Count > BufSize then 

             N := BufSize 

           else

              N := Count;

           Source.ReadBuffer(Buffer^, N);

           WriteBuffer(Buffer^, N);

           Dec(Count, N);

         end;

       finally

         FreeMem(Buffer, BufSize);

       end;

     end;

 

  ⑵ ReadBuffer 方法和 WriteBuffer 方法

   ReadBuffer 方法和 WriteBuffer 方法简单地调用虚拟函数 Read Write 来读写流中数据,它比 Read Write 增加了读写数据出错时的异常处理。

 

     procedure TStream.ReadBuffer(var Buffer; Count: Longint);

     begin

       if (Count <> 0) and (Read(Buffer, Count) <> Count) then

         raise EReadError.CreateRes(SReadError);

     end;

 

     procedure TStream.WriteBuffer(const Buffer; Count: Longint);

     begin

       if (Count <> 0) and (Write(Buffer, Count) <> Count) then

         raise EWriteError.CreateRes(SWriteError);

     end;

 

  ⑶ ReadComponent ReadResHeader ReadComponentRes 方法

   ReadComponent 方法从当前流中读取部件。在实现上 ReadComponent 方法创建了一个 TStream 对象,并用 TReader ReadRootComponent 方法读部件。在 Delphi 对象式管理中, Stream 对象和 Filer 对象结合很紧密。 Stream 对象的许多方法的实现需要 Filer 对象的支持,而 Filer 对象的构造函数

直接就以 Stream 对象为参数。在 ReadComponent 方法的实现中就可清楚地看到这一点:

 

     function TStream.ReadComponent(Instance: TComponent): TComponent;

     var

       Reader: TReader;

     begin

       Reader := TReader.Create(Self, 4096);

       try

         Result := Reader.ReadRootComponent(Instance);

       finally

          Reader.Free;

       end;

     end;

 

     ReadResHeader 方法用于读取 Windows 资源文件的文件头,由 ReadComponentRes 方法在读取 Windows 资源文件中的部件时调用,通常程序员不需自己调用。如果读取的不是资源文件 ReadResH := FSize + Offset;

           end;

           Result := FPosition;

         end;

 

   Offse 代表移动的偏移量。 Origin 代表移动的起点,值为 0 表示从文件头开始,值为 1 表示从当前位置开始,值为 2 表示从文件尾往前,这时 OffSet 一般为负数。 Seek 的实现没有越界的判断。

   3. SaveToStream SaveToFile 方法

   SaveToStream 方法是将 MemoryStream 对象中的内容写入 Stream 所指定的流。其实现如下:

 

         procedure TCustomMemoryStream.SaveToStream(Stream: TStream);

         begin

           if FSize <> 0 then Stream.WriteBuffer(FMemory^, FSize);

         end;

 

   SaveToStream 方法调用了 Stream WriteBuffer 方法,直接将 FMemory 中的内容按 FSize 字节长度写入流中。

   SaveToFile 方法是与 SaveToStream 方法相关的。 SaveToFile 方法首先创建了一个 FileStream 对象,然后把该文件 Stream 对象作为 SaveToStream 的参数,由 SaveToStream 方法执行写操作,其实现如下:

 

         procedure TCustomMemoryStream.SaveToFile(const FileName: string);

         var

           Stream: TStream;

         begin

           Stream := TFileStream.Create(FileName, fmCreate);

           try

             SaveToStream(Stream);

           finally

             Stream.Free;

           end;

         end;

 

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

 

TMemoryStream 对象

 

    

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

介绍它的这些属性和方法。

 

TMemoryStream 的属性和方法

 

   1. Capacity 属性

  声明: property Copacity: Longint; 

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

   2. Realloc 方法

  声明: function Realloc(var NewCapacity: Longint): Pointer; virtual; 

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

   3. SetSize 方法

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

     4. Clear 方法

  声明: procedure Clear; 

     Clear 方法释放内存中的内存池,并将 Memory 属性置为 nil 。在调用 Clear 方法后, Size Position 属性都为 0

   5. LoadFromStream 方法

  声明: procedure LoadFromStream(Stream: TStream); 

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

   6. LoadFromFile 方法

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

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

 

TMemoryStream 对象的实现原理

 

   TMemoryStream TCustomMemoryStream 对象直接继承,因此可以享用 TCustomMemoryStream 的属性和方法。前面讲过, TCustomMemoryStream 是用于内存中数据操作的抽象对象,它为 MemoryStream 对象的实现提供了框架,框架中的内容还要由具体 MemoryStream 对象去填充。 TMemoryStrea

m 对象就是按动态内存管理的需要填充框架中的具体内容。下面介绍 TMemoryStream 对象的实 ? FBuffer := AllocMem(FDataSet.RecordSize);

               FRecord := FBuffer;

               if not FDataSet.GetCurrentRecord(FBuffer) then Exit;

               OpenMode := dbiReadOnly;

         end else

             begin

               if 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;

         begin

           if FOpened then

           begin

             if FModified then FField.FModified := True;

             if not FField.FModified then

               DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);

           end;

           if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize);

           if FModified then

           try

             FField.DataChanged;

           except

             Application.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 编程中很重要,即一定要修改相应数据库部件的状态。

   2. Read Write 方法的实现

   Read Write 方法都调用 BDE API 函数完成数据库 BLOB 字段的读写,其实现如下:

  

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

         var

            Status: DBIResult;

         begin

           Result := 0;

           if FOpened then

           begin

             Status := DbiGetBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,

                                                             Count, @Buffer, Result);

             case Status of

               DBIERR_NONE, DBIERR_ENDOFBLOB:

                 begin

                   if FField.FTransliterate then

                     NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result);

                   Inc(FPosition, Result);

                 end;

               DBIERR_INVALIDBLOBOFFSET:

                 {Nothing};

             else

               DbiError(Status);

             end;

           end;

         end;

 

   Read 方法使用了 BDE 

API DbiGetBlob 函数从 FDataSet 中读取数据,在本函数中,各参数的含义是这样的: FDataSet.Handle 代表 DataSet BDE 句柄, FReacord 表示 BLOB 字段所在记录, FFieldNo 表示 BLOB 字段号, FPosition 表示要读的的数据的起始位置, Count 表示要读的字节数, Buffer 是读出数据所占的内存,

Result 是实际读出的字节数。该 BDE 函数返回函数调用的错误状态信息。

   Read 方法还调用了 NativeToAnsiBuf 进行字符集的转换。

 

         function TBlobStream.Write(const Buffer; Count: Longint): Longint;

         var

           Temp: Pointer;

         begin

           Result := 0;

           if FOpened then

           begin

             if FField.FTransliterate then

              begin

               GetMem(Temp, Count);

               try

                 AnsiToNativeBuf(FDataSet.Locale, @Buffer, Temp, Count);

                 Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,

                   Count, Temp));

               finally

                 FreeMem(Temp, Count);

               end;

             end else

               Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,

                                                       Count, @Buffer));

             Inc(FPosition, Count);

             Result := Count;

             FModified := True;

           end;

         end;

 

     Write 方法调用了 BDE API DbiPutBlob 函数实现往数据库 BLOB 字段存储数据。

     该函数的各参数含义如下:

 

                  调用函数 DbiPutBlob 的各传入参数的含义

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

       参数名           含义

     ──────────────────────────────

        FDataSetHandle            写入的数据库的 BDE 句柄

       FRecord                   写入数据的 BLOB 字段所在的记录

        FFieldNo                  BLOB 字段号

         FPosition                  写入的起始位置

        Count                     写入的数据的字节数

         Buffer                     所写入的数据占有的内存地址

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

 

标志,该标志意味着后面存储有一连串的项目。 Reader 对象,在读这一连串项目时先调用 ReadListBegin 方法读取该标志位,然后用 EndOfList 判断是否列表结束,并用循环语句读取项目。在调用 WriteListBegin 方法的后面必须调用 WriteListEnd 方法写列表结束标志,相应的在 Reader 对象中

ReadListEnd 方法读取该结束标志。

   5. WriteListEnd 方法

  声明: procedure WriteListEnd; 

     WriteListEnd 方法在流中,写入项目列表结束标志,它是与 WriteListBegin 相匹配的方法。

   6. WriteBoolean 方法

  声明: procedure WriteBoolean(Value: Boolean); 

     WriteBoolean 方法将 Value 传入的布尔值写入流中。

   7. WriteChar 方法

  声明: procedure WriteChar(Value: char); 

     WriteChar 方法将 Value 中的字符写入流中。

   8. WriteFloat 方法

  声明: procedure WriteFloat(Value: Extended); 

     WriteFloat 方法将 Value 传入的浮点数写入流中。

   9. WriteInteger 方法

  声明: procedure WriteInteger(Value: Longint); 

     WriteInteger 方法将 Value 中的整数写入流中。

   10. WriteString 方法

  声明: procedure WriteString(const Value: string); 

     WriteString 方法将 Value 中的字符串写入流中。

   11. WriteIdent 方法

  声明: procedure WriteIdent(const Ident: string); 

     WriteIdent 方法将 Ident 传入的标识符写入流中。

   12. WriteSignature 方法

  声明: procedure WriteSignature; 

     WriteSignature 方法将 Delphi Filer 对象标签写入流中。 WriteRootComponent 方法在将部件写入流之前先调用 WriteSignature 方法写入 Filer 标签。 Reader 对象在读部件之前调用 ReadSignature 方法读取该标签以指导读操作。

   13. WritComponent 方法

  声明: procedure WriteComponent(Component: TComponent); 

     WriteComponent 方法调用参数 Component WriteState 方法将部件写入流中。在调用 WriteState 之前, WriteComponent 还将 Component ComponetnState 属性置为 csWriting 。当 WriteState 返回时再清除 csWriting.

     14. WriteRootComponent 方法

  声明: procedure WriteRootComponent(Root: TComponent); 

     WriteRootComponent 方法将 Writer 对象 Root 属性设为参数 Root 带的值,然后调用 WriteSignature 方法往流中写入 Filer 对象标签,最后调用 WriteComponent 方法在流中存储 Root 部件。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值